Merge "Fix quick switch in between two split pairs crash" into tm-qpr-dev
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 951be4e..0c7b48fe 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -40,6 +40,7 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <uses-permission android:name="android.permission.VIBRATE"/>
<!-- for rotating surface by arbitrary degree -->
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
diff --git a/OWNERS b/OWNERS
index 560b562..2d7a014 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,31 +4,37 @@
# People who can approve changes for submission
#
-alexchau@google.com
-andraskloczl@google.com
-patmanning@google.com
adamcohen@google.com
-hyunyoungs@google.com
-mrcasey@google.com
-sunnygoyal@google.com
+alexchau@google.com
+andonian@google.com
awickham@google.com
-twickham@google.com
-winsonc@google.com
-zakcohen@google.com
-santie@google.com
-vadimt@google.com
-jonmiranda@google.com
-pinyaoting@google.com
-gwasserman@google.com
-jamesoleary@google.com
-joshtrask@google.com
-mrenouf@google.com
-mkephart@google.com
-hwwang@google.com
-tracyzhou@google.com
-peanutbutter@google.com
-xuqiu@google.com
+brdayauon@google.com
brianji@google.com
+captaincole@google.com
+charlander@google.com
+fbaron@google.com
+ganjam@google.com
+hwwang@google.com
+hyunyoungs@google.com
+jagrutdesai@google.com
+jeremysim@google.com
+jiuyu@google.com
+jonmiranda@google.com
+kylim@google.com
+patmanning@google.com
+peanutbutter@google.com
+pinyaoting@google.com
+randypfohl@google.com
+saumyaprakash@google.com
+sihua@google.com
+sunnygoyal@google.com
+tracyzhou@google.com
+tsuharesu@google.com
+twickham@google.com
+vadimt@google.com
+victortulias@google.com
+winsonc@google.com
+xuqiu@google.com
per-file FeatureFlags.java, globs = set noparent
-per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, zakcohen@google.com, mrcasey@google.com, adamcohen@google.com, hyunyoungs@google.com
+per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com, captaincole@google.com
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index c8a7d85..c638ba9 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -130,7 +130,7 @@
optional int32 cardinality = 2;
}
-// Next value 43
+// Next value 44
enum Attribute {
UNKNOWN = 0;
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
@@ -176,6 +176,7 @@
ALL_APPS_SEARCH_RESULT_ASSISTANT_MEMORY = 31;
ALL_APPS_SEARCH_RESULT_VIDEO = 41;
ALL_APPS_SEARCH_RESULT_SYSTEM_POINTER = 42;
+ ALL_APPS_SEARCH_RESULT_EDUCARD = 43;
// Web suggestions provided by AGA
ALL_APPS_SEARCH_RESULT_WEB_SUGGEST = 39;
diff --git a/quickstep/res/drawable/close_icon.xml b/quickstep/res/drawable/close_icon.xml
deleted file mode 100644
index 07f4336..0000000
--- a/quickstep/res/drawable/close_icon.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="#909090"
- android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
-</vector>
diff --git a/quickstep/res/drawable/hotseat_icon.xml b/quickstep/res/drawable/hotseat_icon.xml
new file mode 100644
index 0000000..b849fe9
--- /dev/null
+++ b/quickstep/res/drawable/hotseat_icon.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/mock_app_icon" />
+ <corners android:radius="@dimen/gesture_tutorial_hotseat_icon_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/hotseat_icon_home.xml b/quickstep/res/drawable/hotseat_icon_home.xml
new file mode 100644
index 0000000..d59dd4a
--- /dev/null
+++ b/quickstep/res/drawable/hotseat_icon_home.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/gesture_home_tutorial_background" />
+ <corners android:radius="@dimen/gesture_tutorial_hotseat_icon_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/hotseat_search_bar.xml b/quickstep/res/drawable/hotseat_search_bar.xml
new file mode 100644
index 0000000..ea332e9
--- /dev/null
+++ b/quickstep/res/drawable/hotseat_search_bar.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/mock_search_bar" />
+ <corners android:radius="@dimen/gesture_tutorial_hotseat_search_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_desktop.xml b/quickstep/res/drawable/ic_desktop.xml
new file mode 100644
index 0000000..dfaf8b8
--- /dev/null
+++ b/quickstep/res/drawable/ic_desktop.xml
@@ -0,0 +1,31 @@
+<?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="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0"
+ >
+ <group android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="6.0"
+ android:translateY="6.0">
+ <path
+ android:fillColor="?android:attr/textColorPrimary"
+ android:pathData="M5.958,37.708Q4.458,37.708 3.354,36.604Q2.25,35.5 2.25,34V18.292Q2.25,16.792 3.354,15.688Q4.458,14.583 5.958,14.583H9.5V5.958Q9.5,4.458 10.625,3.354Q11.75,2.25 13.208,2.25H34Q35.542,2.25 36.646,3.354Q37.75,4.458 37.75,5.958V21.667Q37.75,23.167 36.646,24.271Q35.542,25.375 34,25.375H30.5V34Q30.5,35.5 29.396,36.604Q28.292,37.708 26.792,37.708ZM5.958,34H26.792Q26.792,34 26.792,34Q26.792,34 26.792,34V21.542H5.958V34Q5.958,34 5.958,34Q5.958,34 5.958,34ZM30.5,21.667H34Q34,21.667 34,21.667Q34,21.667 34,21.667V9.208H13.208V14.583H26.833Q28.375,14.583 29.438,15.667Q30.5,16.75 30.5,18.25Z"/>
+ </group>
+</vector>
diff --git a/quickstep/res/drawable/ic_empty_desktop.xml b/quickstep/res/drawable/ic_empty_desktop.xml
new file mode 100644
index 0000000..cbf1856
--- /dev/null
+++ b/quickstep/res/drawable/ic_empty_desktop.xml
@@ -0,0 +1,25 @@
+<?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="92dp"
+ android:height="80dp"
+ android:tint="?android:attr/textColorPrimary"
+ android:viewportHeight="80.0"
+ android:viewportWidth="92.0">
+ <path
+ android:fillColor="#AAFFFFFF"
+ android:pathData="M 14.365954,80 Q 10.981668,80 8.4908345,77.509166 6,75.018332 6,71.634046 V 36.193807 q 0,-3.384286 2.4908345,-5.87512 2.4908335,-2.493091 5.8751195,-2.493091 H 22.35738 V 8.365954 q 0,-3.3842855 2.538217,-5.8751198 Q 27.433811,0 30.723337,0 h 46.910711 q 3.479041,0 5.969878,2.4908342 2.490834,2.4908343 2.490834,5.8751198 v 35.442495 q 0,3.384286 -2.490834,5.87512 -2.490837,2.490835 -5.969878,2.490835 h -7.896671 v 19.459642 q 0,3.384286 -2.49083,5.87512 Q 64.755713,80 61.371423,80 Z m 0,-8.365954 h 47.005469 q 0,0 0,0 0,0 0,0 V 43.526426 H 14.365954 v 28.10762 q 0,0 0,0 0,0 0,0 z M 69.737377,43.808449 h 7.896671 q 0,0 0,0 0,0 0,0 V 15.698573 H 30.723337 v 12.127023 h 30.740592 q 3.479048,0 5.877376,2.445711 2.396072,2.443454 2.396072,5.82774 z" />
+</vector>
diff --git a/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml b/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
new file mode 100644
index 0000000..286a3c4
--- /dev/null
+++ b/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurfaceVariant" />
+ <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+</shape>
diff --git a/quickstep/res/drawable/keyboard_quick_switch_task_view_background.xml b/quickstep/res/drawable/keyboard_quick_switch_task_view_background.xml
new file mode 100644
index 0000000..d0aac8c
--- /dev/null
+++ b/quickstep/res/drawable/keyboard_quick_switch_task_view_background.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/transparent" />
+ <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+</shape>
diff --git a/quickstep/res/drawable/keyboard_quick_switch_view_background.xml b/quickstep/res/drawable/keyboard_quick_switch_view_background.xml
new file mode 100644
index 0000000..19aaed4
--- /dev/null
+++ b/quickstep/res/drawable/keyboard_quick_switch_view_background.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?attr/overviewScrimColor" />
+ <corners android:radius="@dimen/keyboard_quick_switch_view_radius" />
+</shape>
diff --git a/quickstep/res/drawable/top_task_view.xml b/quickstep/res/drawable/top_task_view.xml
new file mode 100644
index 0000000..d2176c3
--- /dev/null
+++ b/quickstep/res/drawable/top_task_view.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/gesture_tutorial_fake_previous_task_view_color" />
+ <corners android:radius="@dimen/gesture_tutorial_small_task_view_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
index 1e2e014..c7e176a 100644
--- a/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout-land/gesture_tutorial_mock_hotseat.xml
@@ -24,54 +24,50 @@
android:paddingStart="56dp"
android:paddingEnd="56dp">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintVertical_chainStyle="spread_inside"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_2"
app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1"
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_3"
app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_2"
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_4"
app:layout_constraintStart_toStartOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_3"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
index f04fbb6..28d32a4 100644
--- a/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout-land/gesture_tutorial_tablet_mock_hotseat.xml
@@ -22,84 +22,77 @@
android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_search_bar"
android:layout_width="200dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
+ android:background="@drawable/hotseat_search_bar"
+ android:clipToOutline="true"
- app:layout_constraintHorizontal_chainStyle="spread_inside"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardBackgroundColor="@color/mock_search_bar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_1"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_search_bar"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_5"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
new file mode 100644
index 0000000..18c0e1f
--- /dev/null
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -0,0 +1,52 @@
+<?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.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:importantForAccessibility="yes"
+ android:background="@drawable/keyboard_quick_switch_task_view_background"
+ android:clipToOutline="true"
+ launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
+
+ <include
+ layout="@layout/keyboard_quick_switch_thumbnail"
+ android:id="@+id/thumbnail1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/thumbnail2"/>
+
+ <include
+ layout="@layout/keyboard_quick_switch_thumbnail"
+ android:id="@+id/thumbnail2"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_split_view_spacing"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/thumbnail1"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 8eeef67..3bd0df0 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -57,33 +57,34 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
- <androidx.cardview.widget.CardView
+
+ <View
android:id="@+id/top_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:visibility="invisible"
android:layout_marginBottom="@dimen/gesture_tutorial_multi_row_task_view_spacing"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
+ android:visibility="invisible"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
app:layout_constraintVertical_chainStyle="spread"
- app:layout_constraintTop_toTopOf="@id/full_task_view"
app:layout_constraintBottom_toTopOf="@id/bottom_task_view"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
+ app:layout_constraintTop_toTopOf="@id/full_task_view" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/bottom_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
android:visibility="invisible"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
- app:layout_constraintTop_toBottomOf="@id/top_task_view"
app:layout_constraintBottom_toBottomOf="@id/full_task_view"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
+ app:layout_constraintTop_toBottomOf="@id/top_task_view" />
</com.android.quickstep.interaction.AnimatedTaskView>
diff --git a/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
index 8513dcf..8ee0339 100644
--- a/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
@@ -8,67 +8,62 @@
android:paddingStart="26dp"
android:paddingEnd="26dp">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintEnd_toEndOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_search_bar"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardBackgroundColor="@color/mock_search_bar"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
diff --git a/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
index 363f14e..63c51e8 100644
--- a/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
+++ b/quickstep/res/layout/gesture_tutorial_tablet_mock_hotseat.xml
@@ -22,84 +22,78 @@
android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_search_bar"
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
+ android:background="@drawable/hotseat_search_bar"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardBackgroundColor="@color/mock_search_bar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_5"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon"
+ android:clipToOutline="true"
- app:cardElevation="0dp"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardBackgroundColor="@color/mock_app_icon"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_4"
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_overview.xml
new file mode 100644
index 0000000..bf21a3e
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_overview.xml
@@ -0,0 +1,54 @@
+<?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.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:background="@drawable/keyboard_quick_switch_overview_button_background"
+ android:clipToOutline="true"
+ android:importantForAccessibility="yes"
+ launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
+ android:layout_marginBottom="8dp"
+ android:src="@drawable/ic_empty_recents"
+
+ app:tint="?android:attr/textColorPrimary"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/KeyboardQuickSwitchOverview"
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="center"
+
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
new file mode 100644
index 0000000..48e6276
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -0,0 +1,52 @@
+<?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.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:importantForAccessibility="yes"
+ android:background="@drawable/keyboard_quick_switch_task_view_background"
+ android:clipToOutline="true"
+ launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
+
+ <include
+ layout="@layout/keyboard_quick_switch_thumbnail"
+ android:id="@+id/thumbnail1"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/thumbnail2"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <include
+ layout="@layout/keyboard_quick_switch_thumbnail"
+ android:id="@+id/thumbnail2"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:visibility="gone"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_split_view_spacing"
+
+ app:layout_constraintTop_toBottomOf="@id/thumbnail1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml b/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
new file mode 100644
index 0000000..cd6587c
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"
+ android:background="@drawable/keyboard_quick_switch_task_view_background"
+ android:clipToOutline="true"/>
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
new file mode 100644
index 0000000..5c20a2d
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingVertical="@dimen/keyboard_quick_switch_view_spacing"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_margin_top"
+ android:layout_marginHorizontal="@dimen/keyboard_quick_switch_margin_ends"
+ android:background="@drawable/keyboard_quick_switch_view_background"
+ android:clipToOutline="true"
+ android:alpha="0"
+ android:visibility="invisible"
+ android:focusableInTouchMode="true">
+
+ <HorizontalScrollView
+ android:id="@+id/scroll_view"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:scrollbars="none"
+ android:alpha="0"
+ android:visibility="invisible"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ </HorizontalScrollView>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchView>
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index 13b7238..13482ac 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -57,29 +57,29 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+
+ <View
android:id="@+id/top_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="@dimen/gesture_tutorial_multi_row_task_view_spacing"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
android:visibility="invisible"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintBottom_toTopOf="@id/bottom_task_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="@id/full_task_view"
- app:layout_constraintVertical_chainStyle="spread" />
+ app:layout_constraintTop_toTopOf="@id/full_task_view" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/bottom_task_view"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:background="@drawable/top_task_view"
+ android:clipToOutline="true"
android:visibility="invisible"
- app:cardCornerRadius="@dimen/gesture_tutorial_small_task_view_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintBottom_toBottomOf="@id/full_task_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -99,13 +99,13 @@
android:background="@drawable/gesture_tutorial_ripple" />
<include
- layout="@layout/gesture_tutorial_tablet_mock_taskbar"
android:id="@+id/gesture_tutorial_fake_taskbar_view"
- android:layout_width="match_parent"
- android:layout_height="@dimen/gesture_tutorial_mock_taskbar_height"
+ layout="@layout/gesture_tutorial_tablet_mock_taskbar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentEnd="true" />
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="@dimen/gesture_tutorial_taskbar_margin_bottom" />
<ImageView
android:id="@+id/gesture_tutorial_edge_gesture_video"
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
index 6d9ffae..b1c8b31 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_mock_hotseat.xml
@@ -21,70 +21,64 @@
android:layout_height="wrap_content"
android:paddingBottom="70dp"
android:paddingStart="26dp"
- android:paddingEnd="26dp"
- android:background="@color/gesture_home_tutorial_swipe_up_rect">
+ android:paddingEnd="26dp">
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_1"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_2"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_3"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:id="@+id/hotseat_icon_4"
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.cardview.widget.CardView
+ <View
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
+ android:background="@drawable/hotseat_icon_home"
+ android:clipToOutline="true"
- app:cardBackgroundColor="@color/gesture_home_tutorial_background"
- app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
- app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1" />
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index bd11c1e..1642fd4 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -17,11 +17,14 @@
file, they need to be loaded at runtime. -->
<com.android.quickstep.views.TaskView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:defaultFocusHighlightEnabled="false"
- android:focusable="true">
+ android:focusable="true"
+ launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
<com.android.quickstep.views.TaskThumbnailView
android:id="@+id/snapshot"
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 2a9674f..f454835 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -17,12 +17,33 @@
<com.android.quickstep.views.DesktopTaskView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="true"
android:clipToOutline="true"
android:defaultFocusHighlightEnabled="false"
- android:focusable="true">
+ android:focusable="true"
+ launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
+
+ <View
+ android:id="@+id/background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <TextView
+ android:id="@+id/empty_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginTop="@dimen/overview_task_margin"
+ android:drawablePadding="@dimen/recents_empty_message_text_padding"
+ android:text="@string/recents_empty_desktop_message"
+ android:textColor="?android:textColorPrimary"
+ android:textSize="@dimen/recents_empty_message_text_size"
+ android:drawableTop="@drawable/ic_empty_desktop"
+ android:drawableTint="?android:attr/textColorPrimary" />
<!--
TODO(b249371338): DesktopTaskView extends from TaskView. TaskView expects TaskThumbnailView
@@ -38,10 +59,9 @@
<com.android.quickstep.views.IconView
android:id="@+id/icon"
- android:layout_width="0dp"
- android:layout_height="0dp"
+ android:layout_width="@dimen/task_thumbnail_icon_size"
+ android:layout_height="@dimen/task_thumbnail_icon_size"
android:focusable="false"
- android:importantForAccessibility="no"
- android:visibility="gone" />
+ android:importantForAccessibility="no" />
</com.android.quickstep.views.DesktopTaskView>
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index ec03c69..a8d5b50 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -22,11 +22,14 @@
<com.android.quickstep.views.GroupedTaskView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:defaultFocusHighlightEnabled="false"
- android:focusable="true">
+ android:focusable="true"
+ launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
<com.android.quickstep.views.TaskThumbnailView
android:id="@+id/snapshot"
diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml
index 6b665e5..c50db2e 100644
--- a/quickstep/res/layout/taskbar_all_apps_button.xml
+++ b/quickstep/res/layout/taskbar_all_apps_button.xml
@@ -21,5 +21,4 @@
android:layout_height="@dimen/taskbar_icon_min_touch_size"
android:contentDescription="@string/all_apps_button_label"
android:backgroundTint="@android:color/transparent"
- android:icon="@drawable/ic_all_apps_button"
/>
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 6558d11..126b22d 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Onlangse programme"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swiep om na tuisskerm toe te gaan"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swiep op van die onderkant van jou skerm af. Hierdie gebaar neem jou altyd na die tuisskerm toe."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swiep met 2 vingers op van die onderkant van die skerm af. Dié gebaar neem jou altyd na die tuisskerm toe."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Gaan na tuisskerm"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Swiep enige tyd van die onderkant van jou skerm af op om na jou tuisskerm toe te gaan"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Maak seker dat jy van die onderrand van die skerm af opswiep."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Probeer om die venster langer te hou voordat jy laat los."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Maak seker dat jy reguit opswiep en dan onderbreek."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Mooi so!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriaal <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Gereed!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swiep op om na die tuisskerm toe te gaan"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swiep op om na die tuisskerm toe te gaan"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tik op die tuisknoppie om na jou tuisskerm toe te gaan"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Jy is gereed om jou <xliff:g id="DEVICE">%1$s</xliff:g> te begin gebruik"</string>
<string name="default_device_name" msgid="6660656727127422487">"toestel"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Deel"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string>
<string name="action_split" msgid="2098009717623550676">"Verdeel"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op ’n ander app om verdeelde skerm te gebruik"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies nog ’n app as jy verdeelde skerm wil gebruik"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Jou organisasie laat nie hierdie program toe nie"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Slaan navigasietutoriaal oor?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taakbalkopvoeding het verskyn"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taakbalkopvoeding is toegemaak"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Sleep ’n app na die kant toe om 2 apps tegelyk te gebruik"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Stadigswiep op om die Taakbalk te wys"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Kry appvoorstelle op grond van jou roetine"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Skakel gebaarnavigasie in Instellings aan om die Taakbalk outomaties te versteek"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Doen meer met die Taakbalk"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Terug"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasiebalk"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Wys nog # app.}other{Wys nog # apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index a48e450..3269543 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"የቅርብ ጊዜ መተግበሪያዎች"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ወደ መነሻ ለመሄድ ያንሸራትቱ"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ከእርስዎ ማያ ገጽ ግርጌ ላይ ወደ ላይ በጣት ጠረግ ያድርጉ። ይህ የእጅ ውዝዋዜ ሁልጊዜ ወደ መነሻ ማያ ገጽ ይወስድዎታል።"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"በ2 ጣቶች ከማያ ገጹ ግርጌ ወደ ላይ ያንሸራትቱ። ይህ የእጅ ምልክት ሁልጊዜ ወደ መነሻ ማያ ገጽ ይወስደዎታል።"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ወደ መነሻ ይሂዱ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"በማንኛውም ጊዜ ወደ መነሻ ማያ ገጽዎ ለመሄድ ከማያ ገጽዎ የታችኛው ክፍል ወደ ላይ ያንሸራትቱ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ከማያ ገጹ የታችኛው ጫፍ ወደ ላይ ማንሸራተትዎን ያረጋግጡ።"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ከመልቀቅዎ በፊት መስኮቱን ረዘም ላለ ጊዜ ለመያዝ ይሞክሩ።"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"በቀጥታ ወደ ላይ ማንሸራተትዎን ያረጋግጡ፣ ከዚያ ለአፍታ ያቁሙ።"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ጥሩ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"አጋዥ ሥልጠና <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"ሁሉም ዝግጁ!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ወደ መነሻ ለመሄድ በጣት ወደ ላይ ማንሸራተት"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ወደ መነሻ ለመሄድ በጣት ወደ ላይ ይጥረጉ"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ወደ መነሻ ማያ ገጽዎ ለመሄድ የመነሻ አዝራሩን መታ ያድርጉ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"የእርስዎን <xliff:g id="DEVICE">%1$s</xliff:g> መጠቀም ለመጀመር ዝግጁ ነዎት"</string>
<string name="default_device_name" msgid="6660656727127422487">"መሣሪያ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"አጋራ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገጽ እይታ"</string>
<string name="action_split" msgid="2098009717623550676">"ክፈል"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"የተከፈለ ማያ ገጽን ለመቀበል ሌላ መተግበሪያ ይምረጡ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"የአሰሳ አጋዥ ሥልጠናን ይዝለሉ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"የተግባር አሞሌ ትምህርት ይታያል"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"የተግባር አሞሌ ትምህርት ተዘግቷል"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"በአንድ ጊዜ 2 መተግበሪያዎችን ለመጠቀም አንድ መተግበሪያን ወደ ጎን ይጎትቱ"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"የተግባር አሞሌውን ለማሳየት ቀስ ብለው ወደ ላይ ያንሸራትቱ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"በዕለት ተዕለት ተግባርዎ መሠረት የመተግበሪያ አስተያየቶችን ያግኙ"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"የተግባር አሞሌን በራስ ሰር ለመደበቅ የእጅ ምልክት ዳሰሳን በቅንብሮች ውስጥ ያብሩት"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"በተግባር አሞሌው ተጨማሪ ነገር ያድርጉ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ቀጣይ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ተመለስ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"የአሰሳ አሞሌ"</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{ተጨማሪ # መተግበሪያ አሳይ።}one{ተጨማሪ # መተግበሪያ አሳይ።}other{ተጨማሪ # መተግበሪያዎች አሳይ።}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index a78e4d4..b064608 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"شكل مجاني"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"إعدادات استخدام التطبيق"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"محو الكل"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"التطبيقات المستخدمة مؤخرًا"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"مرِّر سريعًا للانتقال إلى الشاشة الرئيسية"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"مرِّر سريعًا من أسفل الشاشة إلى أعلاها. تنقلك هذه الإيماءة دائمًا إلى الشاشة الرئيسية."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"مرِّر سريعًا بإصبعين من أسفل الشاشة إلى أعلاها. تنقلك هذه الإيماءة دائمًا إلى الشاشة الرئيسية."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"الانتقال إلى الشاشة الرئيسية"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"للانتقال إلى شاشتك الرئيسية في أي وقت، اسحب لأعلى الشاشة من أسفلها."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"تأكّد من التمرير سريعًا من الحافة السفلى للشاشة إلى أعلاها."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"حاوِل إبقاء إصبعك على النافذة لمدة أطول قبل رفعه."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"تأكّد من التمرير سريعًا للأعلى مباشرةً ثم التوقّف قليلاً."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"أحسنت"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"الدليل التوجيهي <xliff:g id="CURRENT">%1$d</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"اكتملت عملية الإعداد"</string>
- <string name="allset_hint" msgid="2384632994739392447">"مرِّر سريعًا للأعلى للانتقال إلى الشاشة الرئيسية."</string>
+ <string name="allset_hint" msgid="459504134589971527">"يمكنك التمرير السريع إلى الأعلى للانتقال إلى الشاشة الرئيسية."</string>
<string name="allset_button_hint" msgid="2395219947744706291">"انقر على زر الشاشة الرئيسية للانتقال إلى الشاشة الرئيسية."</string>
<string name="allset_description_generic" msgid="5385500062202019855">"يمكنك الآن بدء استخدام \"<xliff:g id="DEVICE">%1$s</xliff:g>\"."</string>
<string name="default_device_name" msgid="6660656727127422487">"الجهاز"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"مشاركة"</string>
<string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
<string name="action_split" msgid="2098009717623550676">"تقسيم"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"هل تريد تخطي الدليل التوجيهي؟"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ظهرت لوحة تعليم استخدام شريط المهام."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"تم إغلاق لوحة تعليم استخدام شريط المهام."</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"اسحب تطبيقًا إلى جانب الشاشة لاستخدام تطبيقََين في آنٍ واحد."</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"مرِّر ببطء للأعلى لإظهار شريط التطبيقات."</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"احصل على اقتراحات التطبيقات بناءً على سلسلة إجراءاتك."</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"فعِّل خيار \"التنقُّل بالإيماءات\" في \"الإعدادات\" لإخفاء شريط التطبيقات تلقائيًا."</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"إنجاز المزيد باستخدام شريط التطبيقات"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"الشاشة التالية"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"رجوع"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"شريط التنقل"</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{إظهار تطبيق واحد آخر}zero{إظهار # تطبيق آخر}two{إظهار تطبيقَين آخرَين}few{إظهار # تطبيقات أخرى}many{إظهار # تطبيقًا آخر}other{إظهار # تطبيق آخر}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
</resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index cef75f3..e5123a0 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"পিন"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"আটাইবোৰ মচক"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"শেহতীয়া এপসমূহ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"গৃহ স্ক্ৰীনলৈ যাবলৈ ছোৱাইপ কৰক"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"আপোনাৰ স্ক্ৰীনৰ তলৰ অংশৰ পৰা ওপৰলৈ ছোৱাইপ কৰক। এই নিৰ্দেশটোৱে আপোনাক সদায় গৃহ স্ক্ৰীনলৈ লৈ যায়।"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ২ টা আঙুলিৰে ওপৰলৈ ছোৱাইপ কৰক। এই নিৰ্দেশটোৱে আপোনাক সদায় গৃহ স্ক্ৰীনলৈ লৈ যায়।"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"গৃহ পৃষ্ঠালৈ যাওক"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"আপোনাৰ গৃহ স্ক্ৰীনলৈ যিকোনো সময়তে যাবলৈ, আপোনাৰ স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"আপুনি স্ক্ৰীনৰ তলৰ প্ৰান্তৰ পৰা ওপৰলৈ ছোৱাইপ কৰাটো নিশ্চিত কৰক।"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"এৰি দিয়াৰ পূৰ্বে ৱিণ্ডখন দীৰ্ঘ সময়ৰ বাবে ধৰি ৰাখিবলৈ চেষ্টা কৰক।"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"আপুনি স্ক্ৰীনৰ ওপৰলৈ পোনকৈ ছোৱাইপ কৰি তাৰ পাছত ৰোৱাটো নিশ্চিত কৰক।"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"সুন্দৰ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"টিউট’ৰিয়েল <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"সকলো সাজু!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"গৃহ স্ক্ৰীনলৈ যাবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
+ <string name="allset_hint" msgid="459504134589971527">"গৃহ স্ক্ৰীনলৈ যাবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"আপোনাৰ গৃহ স্ক্ৰীনলৈ যাবলৈ গৃহপৃষ্ঠা বুটামটো টিপক"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"আপুনি আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>টো ব্যৱহাৰ কৰিবলৈ সাজু"</string>
<string name="default_device_name" msgid="6660656727127422487">"ডিভাইচ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"শ্বেয়াৰ কৰক"</string>
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string>
<string name="action_split" msgid="2098009717623550676">"বিভাজন কৰক"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছক"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এপ্টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশ্বনৰ টিউট’ৰিয়েল এৰিব বিচাৰে নেকি?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো প্ৰদর্শিত হৈছে"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো বন্ধ হৈছে"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"এবাৰতে ২ টা এপ্ ব্যৱহাৰ কৰিবলৈ কোনো এপ্ কাষলৈ টানি আনি এৰক"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"টাস্কবাৰ দেখুৱাবলৈ লাহেকৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"আপোনাৰ ৰুটিনৰ ওপৰত আধাৰিত এপৰ পৰামৰ্শ পাওক"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"টাস্কবাৰ স্বয়ংক্ৰিয়ভাৱে লুকুৱাবলৈ ছেটিঙত আঙুলিৰ স্পৰ্শৰ নিৰ্দেশেৰে কৰা নেভিগেশ্বন অন কৰক"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"টাস্কবাৰৰ জৰিয়তে অধিক কাৰ্য সম্পাদন কৰক"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"পৰৱৰ্তী"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"উভতি যাওক"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"নেভিগেশ্বনৰ দণ্ড"</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{আৰু # টা এপ্ দেখুৱাওক।}one{আৰু # টা এপ্ দেখুৱাওক।}other{আৰু # টা এপ্ দেখুৱাওক।}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index c6ef81a..e0c3b26 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Son tətbiqlər"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Əsas səhifəyə keçmək üçün sürüşdürün"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Ekranın aşağısından yuxarısına sürüşdürün. Bu jest həmişə Əsas səhifəyə aparır."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 barmaqla ekranın aşağısından yuxarısına sürüşdürün. Bu jest həmişə Əsas səhifəyə aparır."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Əsas səhifəyə qayıdın"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"İstənilən vaxt əsas ekranınıza getmək üçün ekranın aşağısından yuxarı sürüşdürün"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Ekranın ən kənar aşağısından yuxarı sürüşdürün."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Barmağı buraxmadan öncə displeydə bir müddət saxlayın."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Sürüşdürüb ekranın yuxarı kənarında saxlayın."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Əla!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Dərslik <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Hər şey hazırdır!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Əsas səhifəyə keçmək üçün yuxarı çəkin"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Əsas səhifəyə keçmək üçün yuxarı çəkin"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Əsas ekranınıza keçmək üçün əsas düyməyə toxunun"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazından istifadəyə başlamağa hazırsınız"</string>
<string name="default_device_name" msgid="6660656727127422487">"cihaz"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Paylaşın"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skrinşot"</string>
<string name="action_split" msgid="2098009717623550676">"Ayırın"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran üçün başqa tətbiqə toxunun"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Bu əməliyyata tətbiq və ya təşkilatınız tərəfindən icazə verilmir"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Naviqasiya dərsliyi ötürülsün?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tapşırıq panelindəki təlim bölməsi görünür"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tapşırıq panelindəki təlim bölməsi bağlanıb"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Eyni anda 2 tətbiqi istifadə etmək üçün bir tətbiqi yan tərəfə çəkin"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Tapşırıq panelini göstərmək üçün astaca yuxarı sürüşdürün"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Rejiminizə əsasən tətbiq təklifləri alın"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Tapşırıq panelini avtomatik gizlətmək üçün Ayarlarda jest naviqasiyasını aktiv edin"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Tapşırıq paneli ilə daha çox şey edin"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Sonra"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Geri"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naviqasiya paneli"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Daha # tətbiqi göstərin.}other{Daha # tətbiqi göstərin.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 25d2e45..b5db6cc 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Prevucite da biste otišli na početnu stranicu"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prevucite nagore od dna ekrana. Ovaj pokret vas uvek vodi na početni ekran."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Prevucite pomoću dva prsta nagore od dna ekrana. Ovim pokretom uvek otvarate početni ekran."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Idite na početni ekran"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Da biste otišli na početni ekran u bilo kom trenutku, prevucite nagore od dna ekrana."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Obavezno prevucite nagore od donje ivice ekrana."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Probajte da držite prozor duže pre otpuštanja."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Obavezno prevucite pravo nagore, pa zastanite."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Svaka čast!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Gotovo!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Prevucite nagore da biste otvorili početni ekran"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Prevucite nagore da biste otvorili početni ekran"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da bisti išli na početni ekran"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete da koristite <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
@@ -88,8 +88,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>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za podeljeni ekran"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite da preskočite vodič za kretanje?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Traka za navigaciju"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</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>
</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 08a41d0..bb7087f 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Адвольная форма"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налады выкарыстання праграмы"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ачысціць усё"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Нядаўнія праграмы"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Правядзіце пальцам для пераходу на галоўны экран"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Правядзіце пальцам па экране знізу ўверх. Гэты жэст дазваляе вярнуцца на Галоўны экран."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Правядзіце двума пальцамі па экране знізу ўверх. Гэты жэст дазваляе вярнуцца на Галоўны экран."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Перайсці на галоўны экран"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Каб у любы час адкрыць галоўны экран, правядзіце пальцам па экране знізу ўверх"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Пераканайцеся, што праводзіце пальцам па экране знізу ўверх."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Перш чым адпусціць палец, паспрабуйце даўжэй утрымліваць акно націснутым."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Пераканайцеся, што праводзіце пальцам вертыкальна, а потым затрымліваеце яго."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Выдатна!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Дапаможнік <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Гатова!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Каб перайсці на галоўны экран, правядзіце пальцам уверх"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Каб перайсці на галоўны экран, правядзіце пальцам уверх"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Каб перайсці на галоўны экран, націсніце кнопку галоўнага экрана"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Вы можаце пачаць карыстанне прыладай \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
<string name="default_device_name" msgid="6660656727127422487">"прылада"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Абагуліць"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string>
<string name="action_split" msgid="2098009717623550676">"Падзелены экран"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Каб падзяліць экран, націсніце на іншую праграму"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Каб падзяліць экран, выберыце іншую праграму"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Прапусціць дапаможнік па навігацыі?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"З\'явілася панэль навучання на панэлі задач"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Панэль навучання на панэлі задач закрыта"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Каб карыстацца 2 праграмамі, перацягніце адну з іх убок"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Каб паказаць панэль задач, павольна правядзіце пальцам уверх"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Атрымлівайце прапановы праграм з улікам вашых дзеянняў"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Каб аўтаматычна схаваць панэль задач, уключыце ў Наладах навігацыю жэстамі"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Выкарыстоўвайце магчымасці панэлі задач"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Далей"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панэль навігацыі"</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{Паказаць ячшэ # праграму.}one{Паказаць ячшэ # праграму.}few{Паказаць ячшэ # праграмы.}many{Паказаць ячшэ # праграм.}other{Паказаць ячшэ # праграмы.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 2cf4b2a..234b12b 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Фиксиране"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Свободна форма"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма скорошни елементи"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки за използването на приложенията"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Изчистване на всички"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Скорошни приложения"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Жест за преминаване към началния екран"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Прекарайте пръст нагоре от долната част на екрана. Този жест винаги ще ви отвежда до началния екран."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Прекарайте два пръста нагоре от долната част на екрана. Този жест винаги води до началния екран."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Отваряне на началния екран"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"За да отворите началния си екран по всяко време, прекарайте пръст нагоре от долната част на екрана"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Трябва да прекарате пръст нагоре от долния край на екрана."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Задръжте прозореца по-дълго, преди да вдигнете пръста си."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Прекарайте пръст право нагоре, след което задръжте."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Чудесно!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Урок <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Готово!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Прекарайте пръст нагоре, за да отворите началния екран"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Прекарайте пръст нагоре, за да отворите началния екран"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Докоснете бутона „Начало“, за да преминете към началния екран"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Можете да започнете да използвате <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"устройството"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Споделяне"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Екранна снимка"</string>
<string name="action_split" msgid="2098009717623550676">"Разделяне на екрана"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Докоснете друго прил., за да ползвате разд. екран"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"За разделен екран изберете още едно приложение"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Това действие не е разрешено от приложението или организацията ви"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропускане на урока за навигиране?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Показва се урокът за лентата на задачите"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Урокът за лентата на задачите бе затворен"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Плъзнете приложение встрани, за да използвате едновременно 2"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Плъзнете бавно нагоре, за да видите лентата на задачите"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Получавайте предложения за приложения според навиците си"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Включете навигирането с жестове от настройките с цел авт. скриване на лентата на задачите"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повече неща с лентата на задачите"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Напред"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигация"</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_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>
</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 720caa1..2e2ff63 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ফ্রি-ফর্ম"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনো সাম্প্রতিক আইটেম নেই"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"অ্যাপ ব্যবহারের সেটিংস"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"সবকিছু খালি করুন"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"সম্প্রতি ব্যবহৃত অ্যাপ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"হোম স্ক্রিনে যেতে সোয়াইপ করুন"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"স্ক্রিনের নিচের প্রান্ত থেকে উপরের দিকে সোয়াইপ করুন। এটি করলে, আপনি সবসময় হোম স্ক্রিনে যেতে পারবেন।"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"স্ক্রিনের নিচ থেকে ২টি আঙুল দিয়ে উপরে সোয়াইপ করুন। এই জেসচার সবসময় আপনাকে হোম স্ক্রিনে নিয়ে যায়।"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"হোমে যান"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"যেকোনও সময় আপনার হোম স্ক্রিনে যেতে, স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করুন"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"স্ক্রিনের নিচের প্রান্ত থেকে আপনি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিন।"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"চেষ্টা করুন যাতে আঙুল সরিয়ে নেওয়ার আগে উইন্ডো কিছুক্ষণ প্রেস করে রাখা যায়।"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"আপনি উপরের দিকে সোজাসুজি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিয়ে তারপর পজ করুন।"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"সাবাস!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"টিউটোরিয়াল <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"সব রেডি!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"হোম স্ক্রিনে যেতে উপরের দিকে সোয়াইপ করুন"</string>
+ <string name="allset_hint" msgid="459504134589971527">"হোম স্ক্রিনে যেতে উপরের দিকে সোয়াইপ করুন"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"আপনার হোম স্ক্রিনে যাওয়ার জন্য হোম বোতামে ট্যাপ করুন"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> ব্যবহার শুরু করার জন্য আপনি রেডি"</string>
<string name="default_device_name" msgid="6660656727127422487">"ডিভাইস"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"শেয়ার করুন"</string>
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট নিন"</string>
<string name="action_split" msgid="2098009717623550676">"স্প্লিট"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"স্প্লিট স্ক্রিন ব্যবহারের জন্য অ্যাপে ট্যাপ করুন"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশন টিউটোরিয়াল এড়িয়ে যেতে চান?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"নেভিগেশন বার"</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{আরও #টি অ্যাপ দেখুন।}one{আরও #টি অ্যাপ দেখুন।}other{আরও #টি অ্যাপ দেখুন।}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 75ef78b..5c8a887 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodan oblik"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke korištenja aplikacije"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Prevucite da odete na početni ekran"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prevucite s dna ekrana prema gore. Tim pokretom uvijek idete na početni ekran."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Prevucite s 2 prsta od dna ekrana. Tim pokretom uvijek idete na početni ekran"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Odlazak na početni ekran"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Idite na početni ekran u bilo kojem trenutku, prevucite s donjeg dijela ekrana nagore"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Trebate prevući prema gore s donjeg ruba ekrana."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Pokušajte zadržati prozor duže prije puštanja."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Trebate prevući ravno prema gore, a zatim zastati."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Odlično!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Prevucite prema gore da odete na početni ekran"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Prevucite prema gore da odete na početni ekran"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete napočetni ekran"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Sve je spremno da počnete koristiti uređaj <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Dijeli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
<string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu apl. da koristite podijeljeni ekran"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Preskočiti vodič za navigiranje?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigaciona traka"</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 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>
</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 33f01d1..4407cdd 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format lliure"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuració d\'ús d\'aplicacions"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Esborra-ho tot"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacions recents"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Llisca per anar a la pantalla d\'inici"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Llisca cap amunt des de la part inferior de la pantalla. Aquest gest et porta a la pantalla d\'inici."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Llisca amb dos dits cap amunt des de la part inferior. Aquest gest sempre porta a la pantalla d\'inici."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ves a la pàgina d\'inici"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Per anar a la pantalla d\'inici en qualsevol moment, llisca cap amunt des la part inferior"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Assegura\'t de lliscar des de la vora inferior de la pantalla."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prova de mantenir premuda la finestra durant més temps abans de deixar-la anar."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Assegura\'t de lliscar directament cap amunt i després aturar-te."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Molt bé!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Tot a punt!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Llisca cap amunt per anar a la pàgina d\'inici"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Llisca cap amunt per anar a la pàgina d\'inici"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Toca el botó d\'inici per anar a la pantalla d\'inici"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Ja pots començar a utilitzar <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositiu"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Comparteix"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="action_split" msgid="2098009717623550676">"Divideix"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Toca una altra app per utilitzar pantalla dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Tria una altra app per utilitzar pantalla dividida"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vols ometre el tutorial de navegació?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparegut el tauler educatiu de la barra de tasques"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"S\'ha tancat el tauler educatiu de la barra de tasques"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrossega una app al costat per utilitzar 2 apps alhora"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Llisca lentament cap amunt per mostrar la Barra de tasques"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtén suggeriments d\'aplicacions basats en la teva rutina"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"A Configuració, activa la navegació amb gestos per amagar la Barra de tasques automàticament"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Fes més coses amb la Barra de tasques"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Següent"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Enrere"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegació"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # aplicació més.}other{Mostra # aplicacions més.}}"</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>
</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 45516ea..6a38bce 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žádné nedávné položky"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Poslední aplikace"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Přechod na plochu přejetím prstem"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Přejeďte prstem ze spodní části obrazovky nahoru. Tímto gestem se vždy dostanete na plochu."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Přejeďte dvěma prsty z dolního okraje obrazovky nahoru. Tímto gestem se vždy dostanete na plochu."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Přejít na plochu"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Na plochu kdykoli přejdete přejetím prstem ze spodní části obrazovky nahoru"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Přejeďte prstem nahoru z dolního okraje obrazovky."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Zkuste podržet okno delší dobu, než ho uvolníte."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Přejeďte prstem přímo nahoru a pak udělejte pauzu."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Skvělé!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Výukový program <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Hotovo!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Přejetím nahoru se vrátíte na plochu"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Přejetím nahoru se vrátíte na plochu"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Klepnutím na tlačítko plochy se vrátíte na plochu"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Jste připraveni začít používat <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"zařízení"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Sdílet"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
<string name="action_split" msgid="2098009717623550676">"Rozdělit"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Klepnutím na jinou aplikaci rozdělíte obrazovku"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vyberte podporovanou aplikaci"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikace nebo organizace zakazuje tuto akci"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Přeskočit výukový program k navigaci?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila se výuka k hlavnímu panelu"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnímu panelu byla zavřena"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Pokud chcete používat 2 aplikace najednou, přetáhněte aplikaci na stranu"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Panel aplikací zobrazíte pomalým přejetím prstem nahoru"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Získejte návrhy aplikací na základě vašeho používání"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Pokud chcete panel aplikací automaticky skrýt, zapněte v Nastavení navigaci gesty"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Pomocí panelu aplikací můžete dělat více věcí"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Další"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Zpět"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigační panel"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobrazit # další aplikaci.}few{Zobrazit # další aplikace.}many{Zobrazit # další aplikace.}other{Zobrazit # dalších aplikací.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 2e57c9c..a0e636e 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frit format"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Indstillinger for appforbrug"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ryd alt"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Seneste apps"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Stryg for at gå til startskærmen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Stryg opad fra bunden af skærmen. Denne bevægelse åbner altid startskærmen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Stryg opad med 2 fingre fra bunden af skærmen. Denne bevægelse åbner altid startskærmen."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Gå til startskærmen"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Du kan altid gå til startskærmen ved at stryge opad fra bunden af skærmen"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Stryg opad fra bunden af skærmen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prøv at holde fingeren nede på vinduet i længere tid, inden du løfter den."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Stryg lige opad, og hold derefter fingeren stille."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Sådan!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Selvstudie <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Alt er parat!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Stryg opad for at gå til startsiden"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Stryg opad for at gå til startsiden"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tryk på knappen Hjem for at gå til din startskærm"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Du er klar til at bruge din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"enhed"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Del"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Opdel"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vælg en anden app for at bruge opdelt skærm"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du springe selvstudiet for navigation over?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Vejledningen om proceslinjen blev åbnet"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Vejledningen om proceslinjen blev lukket"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Træk en app til siden for at bruge 2 apps på én gang"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Stryg langsomt opad for at se proceslinjen"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appforslag baseret på din rutine"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Aktivér navigation med bevægelser under Indstillinger for automatisk at skjule proceslinjen"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Få mere fra hånden med proceslinjen"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Næste"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tilbage"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationslinje"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app mere.}one{Vis # app mere.}other{Vis # apps mere.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 9d54fca..fe149e1 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Alle Apps schließen"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Kürzlich geöffnete Apps"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Zum Startbildschirm gehen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Displayrand nach oben."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Wische mit zwei Fingern vom unteren Displayrand nach oben. So gelangst du immer zum Startbildschirm."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum Startbildschirm"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Du kannst jederzeit zum Startbildschirm gehen, indem du vom unteren Displayrand nach oben wischst"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Wische vom unteren Displayrand nach oben."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Versuche, das Fenster länger festzuhalten, bevor du es loslässt."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Wische gerade nach oben und halte dann inne."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Sehr gut!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Anleitung <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Fertig!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Nach oben wischen, um den Startbildschirm aufzurufen"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Nach oben wischen, um den Startbildschirm aufzurufen"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Startbildschirmtaste drücken, um zum Startbildschirm zu gehen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Du kannst dein <xliff:g id="DEVICE">%1$s</xliff:g> jetzt verwenden"</string>
<string name="default_device_name" msgid="6660656727127422487">"Gerät"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Teilen"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Teilen"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Für „Geteilter Bildschirm“ auf weitere App tippen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Für geteilten Bildschirm andere App auswählen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigationstutorial überspringen?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Anleitung für Taskleiste eingeblendet"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Anleitung für Taskleiste geschlossen"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"App zur Seite ziehen, um zwei Apps gleichzeitig zu nutzen"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Langsam nach oben wischen, um die Taskleiste anzuzeigen"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"App-Vorschläge auf Grundlage deiner Nutzung erhalten"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Taskleiste automatisch ausblenden: Aktiviere in „Einstellungen“ die Bedienung über Gesten."</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Mehr Möglichkeiten mit der Taskleiste"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Weiter"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Zurück"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationsleiste"</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_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>
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index fe92a40..05c00fb 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Καρφίτσωμα"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Ελεύθερη μορφή"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ρυθμίσεις χρήσης εφαρμογής"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Διαγραφή όλων"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Πρόσφατες εφαρμογές"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Σύρετε για μετάβαση στην αρχική οθόνη"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Σύρετε προς τα πάνω από το κάτω μέρος της οθόνης. Αυτή η κίνηση σάς μεταφέρει πάντα στην αρχ. οθόνη."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Σύρετε από το κάτω άκρο προς τα πάνω με 2 δάχτ. Αυτή η κίνηση σάς μεταφέρει πάντα στην αρχική οθόνη."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Αρχική"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Για μετάβαση στην αρχική οθόνη ανά πάσα στιγμή, σύρετε προς τα επάνω από το κάτω μέρος της οθόνης"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Φροντίστε να σύρετε προς τα επάνω από το κάτω άκρο της οθόνης."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Δοκιμάστε να κρατήσετε περισσότερο το παράθυρο προτού απελευθερώσετε."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Φροντίστε να σύρετε απευθείας προς τα επάνω και έπειτα κάντε παύση."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Ωραία!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Οδηγός <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Όλα έτοιμα!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Σύρετε προς τα πάνω για μετάβαση στην αρχική οθόνη."</string>
+ <string name="allset_hint" msgid="459504134589971527">"Σύρετε προς τα επάνω για να μεταβείτε στην αρχική σελίδα"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Πατήστε το κουμπί αρχικής οθόνης για να μεταβείτε στην αρχική οθόνη"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε το/τη <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"συσκευή"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
<string name="action_split" msgid="2098009717623550676">"Διαχωρισμός"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Πατήστε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Παράβλεψη οδηγού πλοήγησης;"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Η εκπαίδευση για τη γραμμή εργασιών εμφανίστηκε"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Η εκπαίδευση για τη γραμμή εργασιών έκλεισε"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Σύρετε μια εφαρμ. στην άκρη για χρήση δύο εφαρμ. ταυτόχρονα"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Σύρετε αργά προς τα πάνω για εμφάνιση της Γραμμής εργαλείων"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Λάβετε προτεινόμενες εφαρμογές με βάση τη ρουτίνα σας"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Ενεργοπ. την πλοήγηση με κινήσεις στις Ρυθμίσεις για αυτόμ. απόκρυψη της Γραμμής εργαλείων"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Κάντε περισσότερα με τη Γραμμή εργαλείων"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Επόμενο"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Πίσω"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Γραμμή πλοήγησης"</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_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>
</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 485000d..542083c 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swipe to go home"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe up from the bottom of your screen. This gesture always takes you to the home screen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swipe up with two fingers from the bottom of the screen. This gesture always takes you to the home screen."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Go home"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"To go to your home screen at any time, swipe up from the bottom of your screen"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Ready!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go home"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"device"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index fb48a6d..5afc013 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+ <string name="recents_empty_desktop_message" msgid="1358240150311509733">"No desktop items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
@@ -78,7 +79,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"All set!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go Home"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"device"</string>
@@ -86,8 +87,7 @@
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
@@ -118,4 +118,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 485000d..542083c 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swipe to go home"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe up from the bottom of your screen. This gesture always takes you to the home screen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swipe up with two fingers from the bottom of the screen. This gesture always takes you to the home screen."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Go home"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"To go to your home screen at any time, swipe up from the bottom of your screen"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Ready!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go home"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"device"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 485000d..542083c 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swipe to go home"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe up from the bottom of your screen. This gesture always takes you to the home screen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swipe up with two fingers from the bottom of the screen. This gesture always takes you to the home screen."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Go home"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"To go to your home screen at any time, swipe up from the bottom of your screen"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Ready!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go home"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"device"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 257801d..1b9e5d1 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+ <string name="recents_empty_desktop_message" msgid="1358240150311509733">"No desktop items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
@@ -78,7 +79,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"All set!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go Home"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"device"</string>
@@ -86,8 +87,7 @@
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
@@ -118,4 +118,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 97a4b17..1ddb2df 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recientes"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Desliza para ir a la página principal"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Desliza hacia arriba desde la parte inferior de la pantalla. Este gesto te llevará a la pantalla principal."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Desliza hacia arriba desde la parte inferior. Este gesto te llevará siempre a la pantalla principal."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir a la pantalla principal"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Para ir a la pantalla principal en cualquier momento, desliza desde la parte inferior de la pantalla"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Desliza el dedo hacia arriba desde el borde inferior de la pantalla."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prueba mantener presionada la ventana más tiempo antes de soltarla."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Desliza el dedo directamente hacia arriba y luego detente."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"¡Genial!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Instructivo <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Todo listo"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Desliza el dedo hacia arriba para ir a la pantalla principal"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Desliza el dedo hacia arriba para ir a la página principal"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Presiona el botón de inicio para ir a la pantalla principal"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Ya puedes comenzar a usar <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="action_split" msgid="2098009717623550676">"Pantalla dividida"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Presiona otra app para usar la pantalla dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Omitir el instructivo de navegación?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Se abrió la barra de herramientas Educación"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Se cerró la barra de herramientas Educación"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrastra una app a un lado para usar 2 apps a la vez"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Desliza despacio hacia arriba para ver la Barra de tareas"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Recibe sugerencias de aplicaciones basadas en tu rutina"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activa la navegación por gestos en la conf. para ocultar automát. la Barra de tareas"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Haz más con la Barra de tareas"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover a la parte superior o izquierda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover a la parte inferior o derecha"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # app más.}other{Mostrar # apps más.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 3b531cb..f0433af 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay nada reciente"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ajustes de uso de la aplicación"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicaciones recientes"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Desliza para ir a la pantalla de inicio"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Desliza hacia arriba desde la parte inferior de la pantalla. Este gesto siempre te lleva a la pantalla de inicio."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Desliza dos dedos hacia arriba desde la parte inferior de la pantalla. Si haces este gesto, siempre irás a la pantalla de inicio."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir a Inicio"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Para ir a la pantalla de inicio, desliza el dedo hacia arriba desde la parte inferior de la pantalla"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Asegúrate de deslizar el dedo hacia arriba desde el borde inferior de la pantalla."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prueba a mantener pulsada la ventana durante más tiempo antes de soltarla."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Asegúrate de deslizar el dedo directamente hacia arriba y luego mantenlo pulsado."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"¡Muy bien!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"¡Ya está!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Desliza el dedo hacia arriba para ir a la pantalla de inicio"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Desliza el dedo hacia arriba para ir a la pantalla de inicio"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Toca el botón de inicio para ir a la pantalla de inicio"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Ya puedes empezar a usar tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Toca otra app para usar la pantalla dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Saltar tutorial de navegación?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparecido una nota sobre la barra de tareas"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Nota sobre la barra de tareas cerrada"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrastra una aplicación hacia un lado para usar 2 a la vez"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Desliza hacia arriba lentamente para ver la barra de tareas"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtén sugerencias de aplicaciones basadas en tu rutina"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activa la navegación por gestos en Ajustes para ocultar la barra de tareas automáticamente"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Sácale más partido a la barra de tareas"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación más.}other{Mostrar # aplicaciones más.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index d75fed3..0e9c09e 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vabavorm"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Rakenduse kasutuse seaded"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Hiljutised rakendused"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Pühkige avakuvale minemiseks"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pühkige ekraani alaosast üles. See liigutus viib teid alati tagasi avakuvale."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Pühkige ekraanikuva alumisest servast 2 sõrmega üles. See liigutus viib teid alati tagasi avakuvale."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Avalehele"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Mis tahes ajal avakuvale liikumiseks pühkige ekraanikuva allosast üles"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pühkige kindlasti ekraanikuva alumisest servast üles."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Hoidke sõrme aknal pisut kauem, enne kui vabastate."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pühkige kindlasti otse üles, seejärel peatuge."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Tubli töö!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Õpetus <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Valmis!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Avakuvale liikumiseks pühkige üles"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Avalehele liikumiseks pühkige üles"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Avakuvale liikumiseks puudutage avakuva nuppu"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Olete valmis oma seadet <xliff:g id="DEVICE">%1$s</xliff:g> kasutama"</string>
<string name="default_device_name" msgid="6660656727127422487">"seade"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
<string name="action_split" msgid="2098009717623550676">"Eralda"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kas jätta navigeerimise õpetused vahele?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tegumiriba juhised kuvati"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tegumiriba juhised on suletud"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 rakenduse korraga kasutamiseks lohistage rakendus kõrvale"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Tegumiriba kuvamiseks pühkige aeglaselt üles"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Hankige oma rutiini põhjal rakenduste soovitusi"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Tegumiriba automaatseks peitmiseks lülitage seadetes sisse liigutustega navigeerimine"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Tehke tegumiriba abil enamat"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Järgmine"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tagasi"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeerimisriba"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Kuva veel # rakendus.}other{Kuva veel # rakendust.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index ab4931f..cbb1af8 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Modu librea"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Azken aplikazioak"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Pasatu hatza hasierako pantailara joateko"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pasatu hatza pantailaren behealdetik gora. Keinu horrek hasierako pantailara eramango zaitu beti."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Pasatu bi hatz pantailaren behealdetik gora. Hasierako pantailara eramango zaitu beti keinu horrek."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Joan hasierako pantailara"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Hasierako pantailara joateko, pasatu hatza pantailaren behealdetik gora"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Ziurtatu hatza pantailaren beheko ertzetik gora pasatzen duzula."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Eduki sakatuta leihoa luzaroago hatza altxatu aurretik."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Ziurtatu hatza zuzen pasatzen duzula gora; ondoren, gelditu."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Ederki!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriala: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Dena prest!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Pasatu hatza gora hasierako pantailara joateko"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Pasatu hatza gora hasierako pantailara joateko"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Hasierako pantailara joateko, sakatu Hasiera botoia"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Prest zaude <xliff:g id="DEVICE">%1$s</xliff:g> erabiltzen hasteko"</string>
<string name="default_device_name" msgid="6660656727127422487">"gailua"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Partekatu"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
<string name="action_split" msgid="2098009717623550676">"Zatitu"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pantaila zatitua ikusteko, aukeratu beste aplikazio bat"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Nabigazio-tutoriala saltatu nahi duzu?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Agertu egin da zereginen barraren tutoriala"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Itxi egin da zereginen barraren tutoriala"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Bi aplikazio batera erabiltzeko, arrastatu bat albo batera"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Zereginen barra ikusteko, pasatu hatza motel gora"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Jaso erabileran oinarritutako aplikazioen iradokizunak"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Zereginen barra automatikoki ezkutatzeko, aktibatu keinu bidezko nabigazioa ezarpenetan"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Egin gauza gehiago zereginen barrarekin"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Hurrengoa"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atzera"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Nabigazio-barra"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Erakutsi beste # aplikazio.}other{Erakutsi beste # aplikazio.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index b260931..dd64195 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"بدون موارد اخیر"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"برنامههای اخیر"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"تند کشیدن برای رفتن به صفحه اصلی"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"از پایین صفحه، تند بهسمت بالا بکشید. این اشاره همیشه شما را به صفحه اصلی میبرد."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"با ۲ انگشت از پایین صفحه تند بهبالا بکشید. این اشاره همیشه شما را به صفحه اصلی میبرد."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"رفتن به صفحه اصلی"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"برای رفتن به صفحه اصلی در هر زمانی، از پایین صفحه تند بهبالا بکشید"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"دقت کنید که از لبه پایینی صفحه تند به بالا بکشید."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"سعی کنید قبلاز رها کردن، پنجره را برای مدت طولانیتری نگه دارید."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"دقت کنید که مستقیماً تند به بالا بکشید و سپس توقف کنید."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"عالی!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"آموزش گامبهگام <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"همه چیز آماده است!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"برای رفتن به «صفحه اصلی»، تند بهبالا بکشید"</string>
+ <string name="allset_hint" msgid="459504134589971527">"برای رفتن به صفحه اصلی، تند بهبالا بکشید"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"برای رفتن به صفحه اصلی، روی دکمه صفحه اصلی ضربه بزنید"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"آمادهاید از <xliff:g id="DEVICE">%1$s</xliff:g> خود استفاده کنید"</string>
<string name="default_device_name" msgid="6660656727127422487">"دستگاه"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"همرسانی"</string>
<string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
<string name="action_split" msgid="2098009717623550676">"دونیمه"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"زدن روی برنامهای دیگر برای استفاده از صفحه دونیمه"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"انتخاب برنامهای دیگر برای استفاده از صفحه دونیمه"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمیدهد این کنش انجام شود."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"آموزش گامبهگام پیمایش رد شود؟"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"پانل آموزشی نوار وظیفه نمایان شد"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"پانل آموزشی نوار وظیفه بسته شد"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"برای استفاده همزمان از ۲ برنامه، برنامهای را بهکنار بکشید"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"برای نمایش «نوار وظیفه»، انگشتتان را آهسته بهبالا بکشید"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"دریافت «پیشنهادهای برنامه» براساس روال همیشگی"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"برای پنهانسازی خودکار «نوار وظیفه»، پیمایش اشارهای را در «تنظیمات» روشن کنید"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"کارهای بیشتر با «نوار وظیفه» انجام دهید"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"بعدی"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"برگشت"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نوار پیمایش"</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{نمایش # برنامه دیگر.}one{نمایش # برنامه دیگر.}other{نمایش # برنامه دیگر.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 572df68..d517cb7 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vapaamuotoinen"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Sovelluksen käyttöasetukset"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Poista kaikki"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Viimeisimmät sovellukset"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Siirry aloitusnäytölle pyyhkäisemällä"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pyyhkäise ylös näytön alareunasta. Tämä ele vie sinut aina aloitusnäytölle."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Pyyhkäise näytön alareunasta ylöspäin kahdella sormella. Tämä ele vie sinut aina aloitusnäytölle."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Aloitusnäytölle siirtyminen"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Voit siirtyä aloitusnäytölle milloin tahansa pyyhkäisemällä ylös näytön alareunasta"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pyyhkäise ylös näytön alareunasta."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Kokeile pitää ikkunaa painettuna pidempään ennen kuin päästät irti."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Muista pyyhkäistä suoraan ylöspäin ja keskeytä sitten."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Hienoa!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Ohje <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Valmis"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Siirry aloitusnäytölle pyyhkäisemällä ylös"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Siirry aloitusnäytölle pyyhkäisemällä ylös"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Siirry aloitusnäytölle napauttamalla aloitusnäyttöpainiketta"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> on nyt valmis käytettäväksi"</string>
<string name="default_device_name" msgid="6660656727127422487">"Laite"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Jaa"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
<string name="action_split" msgid="2098009717623550676">"Jaa"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Sovellus tai organisaatio ei salli tätä toimintoa"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ohitetaanko navigointiohje?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tehtäväpalkin ohje näkyvissä"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tehtäväpalkin ohje suljettu"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Vedä sovellus sivuun, niin voit käyttää samalla 2 sellaista"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Näytä tehtäväpalkki pyyhkäisemällä ylös hitaasti"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Sovellussuosituksia käytön perusteella"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Laita eleillä navigointi päälle Asetuksista Tehtäväpalkin piilottamiseksi automaattisesti"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Vinkkejä tehtäväpalkin tehokkaampaan käyttöön"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Seuraava"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Takaisin"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigointipalkki"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Näytä # muu sovellus.}other{Näytä # muuta sovellusta.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index b74eba6..13cc7ac 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Balayer pour revenir à l\'écran d\'accueil"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Balayez l\'écran du bas vers le haut. Ce geste vous ramène toujours à l\'écran d\'accueil."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Balayez l\'écran de bas en haut avec deux doigts. Ce geste vous ramène toujours à l\'écran d\'accueil."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Retour à la page d\'accueil"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Pour accéder à votre écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Assurez-vous de balayer l\'écran à partir de l\'extrémité inférieure vers le haut."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Essayez de tenir la fenêtre plus longtemps avant de relâcher."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Assurez-vous de balayer l\'écran vers le haut, puis de faire une pause."</string>
@@ -80,16 +80,15 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bien!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Étape <xliff:g id="CURRENT">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g> du tutoriel"</string>
<string name="allset_title" msgid="5021126669778966707">"Tout est prêt!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Balayez l\'écran vers le haut pour accéder à l\'écran d\'accueil"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Balayez l\'écran vers le haut pour accéder à l\'écran d\'accueil"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Toucher le bouton d\'accueil pour passer sur votre écran d\'accueil"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Vous êtes maintenant prêt à utiliser votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"appareil"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Paramètres de navigation du système"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Partager"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
- <string name="action_split" msgid="2098009717623550676">"Séparé"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="action_split" msgid="2098009717623550676">"Partager"</string>
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre application pour utiliser l\'écran partagé"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'application ou votre organisation n\'autorise pas cette action"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel sur la navigation?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"La barre des tâches éducatives s\'est affichée"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"La barre des tâches éducatives est fermée"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Pour utiliser deux applis, faites-les glisser vers le côté"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Balayez lent. vers le haut pour afficher la barre des tâches"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtenez des suggestions d\'applis en fonction de vos routines"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activez la navigation par gestes dans Paramètres pour masquer auto. la barre des tâches"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Retour"</string>
@@ -122,4 +119,8 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
+ <!-- no translation found for quick_switch_overflow (6935266023013283353) -->
+ <skip />
+ <!-- no translation found for quick_switch_split_task (5598194724255333896) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 8803983..16266f8 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Balayez pour revenir à l\'écran d\'accueil"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Balayez l\'écran de bas en haut. Ce geste vous ramènera toujours à l\'écran d\'accueil."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Balayez l\'écran de bas en haut avec 2 doigts. Ce geste vous ramènera toujours à l\'écran d\'accueil."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Retour à l\'accueil"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Pour accéder à l\'écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Veillez à balayer l\'écran de bas en haut."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Essayez d\'appuyer plus longtemps sur la fenêtre avant de relever le doigt."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Veillez à balayer l\'écran vers le haut, puis à marquer une pause."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bravo !"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriel <xliff:g id="CURRENT">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Tout est prêt !"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Balayez l\'écran vers le haut pour revenir à l\'accueil"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Balayez l\'écran vers le haut pour revenir à l\'accueil"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Appuyez sur le bouton d\'accueil pour accéder à votre écran d\'accueil"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Vous pouvez maintenant utiliser votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"appareil"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Partager"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
<string name="action_split" msgid="2098009717623550676">"Partager"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Appuyez sur autre appli pour l\'écran partagé"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Sélect. autre appli pour utiliser l\'écran partagé"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Cette action n\'est pas autorisée par l\'application ou par votre organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel de navigation ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Infos sur la barre des tâches affichées"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Infos sur la barre des tâches fermées"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Faites glisser une appli sur le côté pour utiliser 2 applis"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Balayez lentement vers haut pour afficher barre des tâches"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtenez des suggestions d\'applis basées sur vos habitudes"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activez la navigation par gestes dans paramètres pour masquage auto de la barre des tâches"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Exploitez les possibilités de la barre des tâches"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Retour"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli.}one{Afficher # autre appli.}other{Afficher # autre applis.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 375cbe9..a51ca6a 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración do uso de aplicacións"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recentes"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Pasa o dedo para ir ao inicio"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pasa o dedo cara arriba desde a parte inferior da pantalla. Ao facelo, irás á pantalla de inicio."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Pasa 2 dedos desde a parte inferior da pantalla. Ao facelo, sempre irás á pantalla de inicio."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir á pantalla de inicio"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Para ir á pantalla de inicio, pasa o dedo cara arriba desde a parte inferior da pantalla"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Asegúrate de pasar o dedo cara arriba desde o bordo inferior da pantalla."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Proba a manter premida a pantalla máis tempo antes de soltala."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Asegúrate de pasar o dedo cara arriba cun movemento vertical. Despois, fai unha pausa."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Excelente!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Titorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Todo listo"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Pasa o dedo cara arriba para ir á pantalla de inicio"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Pasa o dedo cara arriba para ir á pantalla de inicio"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Toca o botón de inicio para ir á pantalla de inicio"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Xa podes comezar a utilizar o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolle outra app para usar a pantalla dividida"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Queres omitir o titorial de navegación?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Panel de información de barra de tarefas aberto"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Panel de información de barra de tarefas pechado"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrastra unha aplicación cara a un lado para usar dúas á vez"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Pasa o dedo amodo cara arriba para ver a barra de tarefas"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtén suxestións de aplicacións en función da túa rutina"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activa navegación con xestos en Configuración e oculta automaticamente a barra de tarefas"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Tira máis proveito da barra de tarefas"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación máis.}other{Mostrar # aplicacións máis.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index d7ead1a..e925a6a 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ફ્રિફોર્મ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ઍપ વપરાશનું સેટિંગ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"બધું સાફ કરો"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"તાજેતરની ઍપ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"હોમ સ્ક્રીન પર જવા માટે સ્વાઇપ કરો"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"તમારી સ્ક્રીનના નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરો. આ સંકેત તમને હંમેશાં હોમ સ્ક્રીન પર લઈ જાય છે."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 આંગળી વડે સ્ક્રીનના સૌથી નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરો. આ સંકેત તમને હંમેશાં હોમ સ્ક્રીન પર લઈ જાય છે."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"હોમ પર જાઓ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"કોઈપણ સમયે તમારી હોમ સ્ક્રીન પર જવા માટે, તમારી સ્ક્રીનની સૌથી નીચેની બાજુએથી ઉપરની તરફ સ્વાઇપ કરો"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ખાતરી કરો કે તમે સ્ક્રીનની નીચેની કિનારીએથી ઉપરની તરફ સ્વાઇપ કરો છો."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"તમારી આંગળી ઊંચકતા પહેલાં તેને વિન્ડો પર થોડી વધારે વાર માટે દબાવી રાખવાનો પ્રયાસ કરો."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ખાતરી કરો કે તમે સીધું ઉપર સ્વાઇપ કરો છો, પછી થોભી જાઓ છો."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"સરસ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ટ્યૂટૉરિઅલ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"બધું સેટ થઈ ગયું!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"હોમપેજ પર જવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
+ <string name="allset_hint" msgid="459504134589971527">"હોમ પર જવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"તમારી હોમ સ્ક્રીન પર જવા માટે હોમ બટન ટૅપ કરો"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"તમે તમારા <xliff:g id="DEVICE">%1$s</xliff:g>નો ઉપયોગ કરવાનું શરૂ કરવા માટે તૈયાર છો"</string>
<string name="default_device_name" msgid="6660656727127422487">"ડિવાઇસ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"શેર કરો"</string>
<string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string>
<string name="action_split" msgid="2098009717623550676">"વિભાજિત કરો"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"વિભાજિત સ્ક્રીન વાપરવા, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"સ્ક્રીન વિભાજનનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"નૅવિગેશન ટ્યૂટૉરિઅલ છોડી દઈએ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ દેખાય છે"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ બંધ થઈ છે"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"એક સાથે 2 ઍપનો ઉપયોગ કરવા માટે, ઍપને ખેંચીને બાજુ પર લઈ જાઓ"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ટાસ્કબાર બતાવવા માટે ઉપરની તરફ ધીમેથી સ્વાઇપ કરો"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"તમારા રૂટિનના આધારે ઍપના સુઝાવો મેળવો"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"ટાસ્કબારને ઑટોમૅટિક રીતે છુપાવવા માટે સેટિંગમાં સંકેતથી નૅવિગેશનની સુવિધા ચાલુ કરો"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"ટાસ્કબાર વડે બીજું ઘણું કરો"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"આગળ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"પાછળ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"નૅવિગેશન બાર"</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{વધુ # ઍપ બતાવો.}one{વધુ # ઍપ બતાવો.}other{વધુ # ઍપ બતાવો.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 2fc4448..90bb17a 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करना"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ़्रीफ़ॉर्म"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हाल ही में इस्तेमाल किया गया कोई ऐप्लिकेशन नहीं है"</string>
+ <string name="recents_empty_desktop_message" msgid="1358240150311509733">"डेस्कटॉप पर कोई आइटम नहीं मिला"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ऐप्लिकेशन इस्तेमाल की सेटिंग"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सभी ऐप्लिकेशन बंद करें"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन"</string>
@@ -61,10 +62,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"होम स्क्रीन पर जाने के लिए स्वाइप करें"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"स्क्रीन पर नीचे से ऊपर की ओर स्वाइप करें. हाथ का यह जेस्चर आपको हमेशा होम स्क्रीन पर ले जाता है."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"स्क्रीन के सबसे नीचे से ऊपर की ओर 2 उंगलियों से स्वाइप करें. जेस्चर हमेशा होम स्क्रीन पर ले जाता है."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"होम स्क्रीन पर जाएं"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"किसी भी समय फ़ोन की होम स्क्रीन पर जाने के लिए, फ़ोन पर सबसे नीचे से ऊपर की ओर स्वाइप करें"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"देख लें कि आप स्क्रीन के निचले किनारे से ऊपर की ओर स्वाइप कर रहे हों."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"कोशिश करें कि स्क्रीन से उंगली उठाने से पहले, इसे कुछ देर स्क्रीन पर दबाकर रखें."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"देख लें कि आप स्क्रीन पर ऊपर की तरफ़, बिलकुल सीधे स्वाइप कर रहे हों और फिर रुकें."</string>
@@ -80,7 +79,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"बहुत बढ़िया!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ट्यूटोरियल <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"हो गया!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"होम स्क्रीन पर जाने के लिए, ऊपर की ओर स्वाइप करें"</string>
+ <string name="allset_hint" msgid="459504134589971527">"होम पेज पर जाने के लिए, ऊपर की ओर स्वाइप करें"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"होम स्क्रीन पर जाने के लिए, होम बटन पर टैप करें"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"आप <xliff:g id="DEVICE">%1$s</xliff:g> को इस्तेमाल करने के लिए तैयार हैं"</string>
<string name="default_device_name" msgid="6660656727127422487">"डिवाइस"</string>
@@ -88,8 +87,7 @@
<string name="action_share" msgid="2648470652637092375">"शेयर करें"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन के लिए दूसरे ऐप्लिकेशन पर टैप करें"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन के लिए, दूसरा ऐप्लिकेशन चुनें"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"क्या आपको नेविगेशन ट्यूटोरियल छोड़ना है?"</string>
@@ -120,4 +118,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेविगेशन बार"</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{# और ऐप्लिकेशन दिखाएं.}one{# और ऐप्लिकेशन दिखाएं.}other{# और ऐप्लिकेशन दिखाएं.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index bf74b0d..66835a4 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke upotrebe aplikacija"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Izbriši sve"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Prijeđite prstom da biste otvorili početni zaslon"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prijeđite prstom od dna zaslona prema gore. Tim pokretom uvijek će se otvoriti početni zaslon."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Prijeđite s dva prsta od dna zaslona prema gore. Tim pokretom uvijek će se otvoriti početni zaslon."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Otvaranje početnog zaslona"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Da biste otvorili početni zaslon, prijeđite prstom od dna zaslona prema gore"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pazite da prijeđete prstom prema gore od donjeg ruba zaslona."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Pokušajte zadržati prozor dulje prije podizanja prsta."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pazite da prijeđete prstom ravno prema gore, a zatim zastanete."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Odlično!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Prijeđite prstom prema gore da biste otvorili početni zaslon"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Prijeđite prstom prema gore da biste otvorili početni zaslon"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite gumb početnog zaslona da biste prešli na početni zaslon"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste za početak upotrebe uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Podijeli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string>
<string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za upotrebu podijeljenog zaslona"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili vaša organizacija ne dopuštaju ovu radnju"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite li preskočiti vodič za kretanje?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigacijska traka"</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_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>
</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 02b7fc3..10086da 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Legutóbbi alkalmazások"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Csúsztatás a kezdőképernyőre lépéshez"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Csúsztassa ujját felfelé a képernyő aljától. Ez a mozdulat mindig a kezdőképernyőre visz."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Csúsztasson felfelé két ujjal a képernyő aljáról. Ez a kézmozdulat mindig a kezdőképernyőre viszi."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ugrás a kezdőképernyőre"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Ha vissza szeretne térni a kezdőképernyőre, bármikor felfelé csúsztathat ujjával a képernyő aljáról"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Csúsztasson felfelé a képernyő aljától."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Próbálja tovább lenyomva tartani az ablakot, mielőtt elengedi a képernyőt."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Csúsztasson egyenesen felfelé, majd várjon egy kicsit."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Remek!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Útmutató (<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="CURRENT">%1$d</xliff:g>.)"</string>
<string name="allset_title" msgid="5021126669778966707">"Kész is!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Felfelé csúsztatva megjelenik a Kezdőképernyő"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Felfelé csúsztatva megjelenik a kezdőképernyő"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"A kezdőképernyőre való lépéshez koppintson a kezdőképernyő gombra"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Készen áll a(z) <xliff:g id="DEVICE">%1$s</xliff:g> használatára"</string>
<string name="default_device_name" msgid="6660656727127422487">"eszköz"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Megosztás"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Képernyőkép"</string>
<string name="action_split" msgid="2098009717623550676">"Felosztás"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Koppintson másik appra az osztott képernyőhöz"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Válasszon másik appot a képernyő felosztásához"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Az alkalmazás vagy az Ön szervezete nem engedélyezi ezt a műveletet"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kihagyja a navigáció bemutatóját?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Az eszköztár használatát ismertető panel megjelent"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Az eszköztár használatát ismertető panel bezárult"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Húzzon egy appot oldalra, ha kettőt használna egyidejűleg"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Csúsztassa ujját lassan fel a Feladatsáv megjelenítéséhez"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Alkalmazásjavaslatokat kaphat a rutinja alapján"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"A Feladatsáv automatikus elrejtéséhez aktiválja a navigációs kézmozdulatokat a beállításokban"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Jobban kihasználhatja a Feladatsávot"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Tovább"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Vissza"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigációs sáv"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# további alkalmazás megjelenítése.}other{# további alkalmazás megjelenítése.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index dcf7cbf..d0d24bb 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Կամայական ձև"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Վերջին տարրեր չկան"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Հավելվածի օգտագործման կարգավորումներ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Վերջին օգտագործած հավելվածները"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Սահեցրեք մատը՝ հիմնական էկրան անցնելու համար"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Մատը սահեցրեք էկրանի ներքևից վերև։ Այս ժեստը բացում է հիմնական էկրանը։"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Երկու մատը էկրանի ներքևից սահեցրեք վերև։ Այս ժեստը բացում է հիմնական էկրանը։"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Անցնել հիմնական էկրան"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Հիմնական էկրան վերադառնալու համար մատը էկրանի ներքևից սահեցրեք վերև"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Համոզվեք, որ մատն էկրանի ներքևի եզրից վերև եք սահեցնում։"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Նախքան բաց թողնելը փորձեք հնարավորինս երկար պահել պատուհանը։"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Համոզվեք, որ մատն ուղիղ վերև եք սահեցնում, այնուհետև դադար տվեք։"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Գերազանց է"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Ուղեցույց <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Պատրաստ է"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Մատը սահեցրեք վերև՝ հիմնական էկրան անցնելու համար"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Մատը սահեցրեք վերև՝ հիմնական էկրան անցնելու համար"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Հիմնական էկրան վերադառնալու համար սեղմեք գլխավոր էկրանի կոճակը"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Դուք արդեն կարող եք օգտագործել ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքը"</string>
<string name="default_device_name" msgid="6660656727127422487">"սարք"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Կիսվել"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Սքրինշոթ անել"</string>
<string name="action_split" msgid="2098009717623550676">"Տրոհել"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Հպեք այլ հավելվածի՝ տրոհված էկրանից օգտվելու համար"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ընտրեք այլ հավելված՝ կիսված էկրանից օգտվելու համար"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Բաց թողնե՞լ նավիգացիայի ուղեցույցը"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Խնդրագոտու «Կրթություն» վահանակը բացվեց"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Խնդրագոտու «Կրթություն» վահանակը փակվեց"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Միաժամանակ օգտագործեք երկու հավելված՝ մեկը մի կողմ քաշելով"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Հավելվածների վահանակը բացելու համար մատը դանդաղ սահեցրեք վեր"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Ստացեք առաջարկներ ձեր գործողությունների հիման վրա"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Կարգավորումներում միացրեք ժեստերով նավիգացիան՝ հավելվածների վահանակը թաքցնելու համար"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Օգտվեք հավելվածների վահանակի բոլոր հնարավորություններից"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Առաջ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Հետ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Նավիգացիայի գոտի"</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{Ցուցադրել ևս # հավելված։}one{Ցուցադրել ևս # հավելված։}other{Ցուցադրել ևս # հավելված։}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index b034bbe..ed9d0ff 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikasi terbaru"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Geser untuk beralih ke layar utama"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Geser ke atas dari bagian bawah layar. Gestur ini akan selalu membawa Anda ke Layar utama."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Geser ke atas dengan 2 jari dari bawah layar. Gestur ini akan selalu membawa Anda ke Layar utama."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Buka layar utama"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Untuk membuka layar utama kapan saja, geser ke atas dari bagian bawah layar"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pastikan Anda menggeser ke atas dari tepi bawah layar."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Coba tahan jendela lebih lama sebelum melepaskan."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pastikan Anda menggeser lurus ke atas, lalu menjedanya."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bagus!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Semua siap."</string>
- <string name="allset_hint" msgid="2384632994739392447">"Geser ke atas untuk beralih ke Layar utama"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Geser ke atas untuk beralih ke layar utama"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Ketuk tombol layar utama untuk membuka layar utama"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Anda sudah siap untuk mulai menggunakan <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"perangkat"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Bagikan"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Pisahkan"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Ketuk apl lain untuk menggunakan layar terpisah"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih aplikasi lain untuk memakai layar terpisah"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Lewati tutorial gestur?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukasi taskbar ditampilkan"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukasi taskbar ditutup"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Tarik aplikasi ke samping untuk menggunakan 2 aplikasi sekaligus"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Geser perlahan ke atas untuk menampilkan Taskbar"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dapatkan saran aplikasi berdasarkan rutinitas Anda"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Aktifkan navigasi gestur di Setelan untuk menyembunyikan otomatis Taskbar"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan banyak hal dengan Taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Berikutnya"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Kembali"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Menu navigasi"</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_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>
</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 8df7134..ffa899f 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nýleg forrit"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Strjúktu til að fara heim"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Strjúktu upp frá neðri hluta skjásins. Þetta flytur þig alltaf á heimaskjáinn."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Strjúktu frá neðri brún skjásins með 2 fingrum. Þessi bending opnar ávallt heimaskjáinn."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Fara á heimaskjá"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Strjúktu upp frá neðsta hluta skjásins til að opna heimskjáinn hvenær sem er"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Passaðu að strjúka upp frá neðri brún skjásins."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prófaðu að halda fingrinum lengur á glugganum áður en þú sleppir."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Passaðu að strjúka beint upp og stoppa svo."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Flott!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Leiðsögn <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Allt tilbúið!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Strjúktu upp til að fara á heimaskjáinn"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Strjúktu upp til að fara á heimaskjáinn"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Ýttu á heimahnappinn til að fara á heimaskjáinn"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Þú getur byrjað að nota <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"tækið"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Deila"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skjámynd"</string>
<string name="action_split" msgid="2098009717623550676">"Skipta"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Ýttu á annað forrit til að nota skjáskiptingu"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Veldu annað forrit til að nota skjáskiptingu"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Forritið eða fyrirtækið leyfir ekki þessa aðgerð"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Sleppa flettileiðsögn?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Leiðsögn verkefnastiku sýnileg"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Leiðsögn verkefnastiku lokað"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Dragðu forrit til hliðar til að nota 2 forrit í einu"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Strjúktu hægt upp til að birta forritastikuna"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Fáðu forritatillögur sem byggjast á rútínunni þinni"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Kveiktu á bendingastjórnun í stillingunum til að fela forritastikuna sjálfkrafa"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Nýttu forritastikuna betur"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Áfram"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Til baka"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Yfirlitsstika"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Sýna # forrit í viðbót.}one{Sýna # forrit í viðbót.}other{Sýna # forrit í viðbót.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index a02e7cc..0cf9ec2 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"App recenti"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Scorri per andare alla schermata Home"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Scorri verso l\'alto dalla parte inferiore dello schermo. Questo gesto ti porta sempre alla schermata Home."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Scorri verso l\'alto con 2 dita dal basso. Questo gesto ti porta sempre alla schermata Home."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Vai alla schermata Home"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Per andare alla schermata Home in qualsiasi momento, scorri sullo schermo dal basso verso l\'alto"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Assicurati di scorrere verso l\'alto dal bordo inferiore dello schermo."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prova a tenere premuta la finestra più a lungo prima di rilasciarla."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Assicurati di scorrere verso l\'alto senza fermarti, poi fai una pausa."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bene!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Finito."</string>
- <string name="allset_hint" msgid="2384632994739392447">"Scorri verso l\'alto per andare alla schermata Home"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Scorri verso l\'alto per andare alla schermata Home"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tocca il pulsante Home per andare alla schermata Home"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Puoi iniziare a usare il tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Condividi"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Dividi"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tocca un\'altra app per usare lo schermo diviso"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Scegli un\'altra app per usare lo schermo diviso"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Questa azione non è consentita dall\'app o dall\'organizzazione"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Saltare il tutorial di navigazione?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra di navigazione"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # altra app.}other{Mostra altre # app.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 6b71ad6..94978ea 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"מצב חופשי"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"הגדרות שימוש באפליקציה"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ניקוי הכול"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"אפליקציות אחרונות"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"יש להחליק כדי לעבור למסך הבית"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"החלקה למעלה מתחתית המסך תמיד תעביר אותך למסך הבית."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"יש להחליק למעלה עם שתי אצבעות מתחתית המסך. התנועה הזו תמיד מעבירה אותך למסך הבית."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"מעבר למסך הבית"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"למעבר למסך הבית בכל שלב, צריך להחליק למעלה מהחלק התחתון של המסך"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"חשוב להקפיד להחליק למעלה מהקצה התחתון של המסך."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"אפשר להחזיק את החלון זמן רב יותר לפני שמשחררים."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"חשוב להקפיד להחליק ישר למעלה ואז להמתין."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"איזה יופי!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"מדריך <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"הכול מוכן!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"כדי לעבור לדף הבית, מחליקים כלפי מעלה"</string>
+ <string name="allset_hint" msgid="459504134589971527">"כדי לחזור לדף הבית, מחליקים כלפי מעלה"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"כדי לעבור אל מסך הבית יש להקיש על הלחצן הראשי"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"הכול מוכן ואפשר להתחיל להשתמש ב<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"מכשיר"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"שיתוף"</string>
<string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string>
<string name="action_split" msgid="2098009717623550676">"פיצול"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"צריך להקיש על אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"לדלג על המדריך לניווט?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"חלונית ההסברים על שורת המשימות מופיעה"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"חלונית ההסברים על שורת המשימות נסגרה"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"כדי להשתמש בשתי אפליקציות בו-זמנית, צריך לגרור אפליקציה לצד"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"צריך להחליק לאט כדי להציג את סרגל האפליקציות"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"קבלת הצעות לאפליקציות על סמך השימוש השגרתי שלך"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"אפשר להפעיל את הניווט באמצעות תנועות ב\'הגדרות\' כדי להסתיר אוטומטית את סרגל האפליקציות"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"פעולות נוספות שאפשר לעשות עם סרגל האפליקציות"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"הבא"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"חזרה"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"סרגל הניווט"</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{הצגת אפליקציה אחת (#) נוספת.}one{הצגת # אפליקציות נוספות.}two{הצגת # אפליקציות נוספות.}other{הצגת # אפליקציות נוספות.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index e1bf1c7..72d2409 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"フリーフォーム"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使ったアプリ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"スワイプでホームに戻る"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"画面を下から上にスワイプします。この操作でいつでもホーム画面に戻れます。"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 本の指で画面下部から上にスワイプします。この操作で常にホーム画面に戻ります。"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ホームに移動"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"画面を下から上にスワイプすると、ホーム画面にいつでも移動できます"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"画面の下端から上にスワイプしてください。"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ウィンドウをもう少し長く押してから指を離すようにしてみましょう。"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"まっすぐ上にスワイプしてから、いったん指を止めてください。"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"成功しました"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"チュートリアル <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"設定完了"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ホームに移動するには上にスワイプします"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ホームに移動するには上にスワイプします"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ホームボタンをタップすると、ホーム画面に移動します"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> を使用する準備ができました"</string>
<string name="default_device_name" msgid="6660656727127422487">"デバイス"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"共有"</string>
<string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"分割画面を使用するには、他のアプリをタップします"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"分割画面にするには、別のアプリを選択してください"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"操作チュートリアルをスキップしますか?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ナビゲーション バー"</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_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>
</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index eca7e44..fc791b5 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"თავისუფალი ფორმა"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"აპების გამოყენების პარამეტრები"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ყველას გასუფთავება"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ბოლოდროინდელი აპები"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"მთავარი გვერდის სანახავად გადაფურცლეთ"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ. ამ ჟესტს ყოველთვის მთავარი გვერდის ეკრანზე გადაყავხართ."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"ორი თითით გადაფურცლეთ ეკრანის ქვედა ნაწილიდან. ეს ჟესტი ყოველთვის მთავარ ეკრანზე გადაგიყვანთ."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"მთავარზე გადასვლა"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ნებისმიერ დროს მთავარ ეკრანზე გადასასვლელად, გადაფურცლეთ ეკრანის ქვემოდან ზემოთ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"უფრო ხანგრძლივად დააჭირეთ თითი ფანჯარას, რომ არ დაიხუროს."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"გადაფურცლეთ პირდაპირ ზემოთ და შემდეგ დააპაუზეთ."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"მშვენიერია!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"სახელმძღვანელო <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"მზადაა!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"მთავარ გვერდზე გადასასვლელად გადაფურცლეთ ზევით"</string>
+ <string name="allset_hint" msgid="459504134589971527">"მთავარ გვერდზე გადასასვლელად გადაფურცლეთ ზევით"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"შეეხეთ მთავარი ეკრანის ღილაკს მთავარ ეკრანზე გადასასვლელად"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"მზად ხართ, გამოიყენოთ <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"მოწყობილობა"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"გაზიარება"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ეკრანის ანაბეჭდი"</string>
<string name="action_split" msgid="2098009717623550676">"გაყოფა"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"შეეხეთ სხვა აპს ეკრანის გასაყოფად"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"აირჩიეთ სხვა აპი ეკრანის გასაყოფად"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ეს მოქმედება არ არის დაშვებული აპის ან თქვენი ორგანიზაციის მიერ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"გსურთ, გამოტოვოთ ნავიგაციის სახელმძღვანელო?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ამოცანების ზოლის სასწავლო არე გამოჩნდა"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ამოცანების ზოლის სასწავლო არე დაიხურა"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 აპის ერთდროულად გამოსაყენებლად გადაათრიეთ აპი კიდეზე"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"მოკლედ გადაფურცლეთ ზემოთ, რომ ამოცანათა ზოლი გამოაჩინოთ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"მიიღეთ აპის შეთავაზებები თქვენი რუტინის მიხედვით"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"ჩართეთ ჟესტებით ნავიგაცია პარამეტრებში, რათა ავტომატურად დაიმალოთ სამუშაო ზოლი"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"გააკეთეთ მეტი ამოცანათა ზოლის მეშვეობით"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"შემდეგი"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"უკან"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ნავიგაციის ზოლი"</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_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>
</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 279a921..414aa17 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Еркін форма"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Қолданбаны пайдалану параметрлері"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Соңғы пайдаланылған қолданбалар"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Негізгі экранға өту үшін сырғытыңыз"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Экранның төменгі жағынан жоғары қарай сырғытыңыз. Сонда негізгі экран ашылады."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Екі саусақпен экранның төменгі жағынан жоғары сырғытыңыз. Бұл қимыл үнемі негізгі экранды ашады."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Негізгі бетке өту"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Кез келген уақытта негізгі экранға өту үшін экранның астыңғы жағынан жоғары қарай сырғытыңыз."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Экранның төменгі шетінен жоғары қарай сырғытыңыз."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Жіберер алдында терезені ұзағырақ ұстап тұруға тырысыңыз."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Тігінен жоғары қарай сырғытыңыз да, кідіріңіз."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Жақсы!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Оқулық: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Бәрі дайын!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Негізгі экранға өту үшін жоғары қарай сырғытыңыз."</string>
+ <string name="allset_hint" msgid="459504134589971527">"Негізгі экранға өту үшін жоғары қарай сырғытыңыз."</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Негізгі экранға өту үшін негізгі экран түймесін түртіңіз."</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> пайдалануға дайын."</string>
<string name="default_device_name" msgid="6660656727127422487">"құрылғы"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Бөлісу"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Бөлу"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Қимылдар оқулығын өткізіп жіберу керек пе?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапсырмалар тақтасы бойынша нұсқаулық ашылды."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Тапсырмалар тақтасы бойынша нұсқаулық жабылды."</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 қолданбаны бір мезгілде пайдалану үшін қолданбаны шетке сүйреңіз."</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Тапсырмалар жолағын көрсету үшін жоғары қарай ақырын сырғытыңыз."</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Іс-әрекеттеріңізге негізделген қолданба ұсыныстарын алыңыз."</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Тапсырмалар жолағын автоматты түрде жасыру үшін параметрлерден қимылмен басқаруды қосыңыз."</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Тапсырмалар жолағы арқылы көп әрекетті орындаңыз"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Келесі"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Артқа"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигация жолағы"</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_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>
</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 53fbfec..3bbc946 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ខ្ទាស់"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"មុខងារទម្រង់សេរី"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ការកំណត់ការប្រើប្រាស់កម្មវិធី"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"សម្អាតទាំងអស់"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"កម្មវិធីថ្មីៗ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"អូសដើម្បីចូលទៅកាន់អេក្រង់ដើម"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"អូសឡើងលើពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក។ ចលនានេះនាំអ្នកទៅអេក្រង់ដើមជានិច្ច។"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"អូសឡើងលើដោយប្រើម្រាមដៃពីរពីផ្នែកខាងក្រោមនៃអេក្រង់។ ចលនានេះតែងតែនាំអ្នកទៅអេក្រង់ដើមជានិច្ច។"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ទៅទំព័រដើម"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ដើម្បីទៅកាន់អេក្រង់ដើមរបស់អ្នកនៅពេលណាក៏បាន សូមអូសឡើងលើពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ត្រូវប្រាកដថាអ្នកអូសឡើងលើពីគែមខាងក្រោមនៃអេក្រង់។"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"សាកល្បងសង្កត់វិនដូឱ្យបានយូរជាងនេះ មុនពេលដកដៃ។"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ត្រូវប្រាកដថាអ្នកអូសត្រង់ឡើងលើ រួចផ្អាក។"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ល្អ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"មេរៀនទី <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"រួចហើយ!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"អូសឡើងលើ ដើម្បីទៅកាន់អេក្រង់ដើម"</string>
+ <string name="allset_hint" msgid="459504134589971527">"អូសឡើងលើ ដើម្បីចូលទៅកាន់អេក្រង់ដើម"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ចុចប៊ូតុងដើម ដើម្បីចូលទៅកាន់អេក្រង់ដើមរបស់អ្នក"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"អ្នកអាចចាប់ផ្ដើមប្រើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានហើយ"</string>
<string name="default_device_name" msgid="6660656727127422487">"ឧបករណ៍"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"ចែករំលែក"</string>
<string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string>
<string name="action_split" msgid="2098009717623550676">"បំបែក"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"ចុចកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះមិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី ឬស្ថាប័នរបស់អ្នកទេ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"រំលងមេរៀនអំពីការរុករកឬ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ការបង្រៀនអំពីរបារកិច្ចការបានបង្ហាញ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ការបង្រៀនអំពីរបារកិច្ចការត្រូវបានបិទ"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"អូសកម្មវិធីទៅចំហៀង ដើម្បីប្រើកម្មវិធី 2 ក្នុងពេលតែមួយ"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"អូសឡើងលើយឺតៗ ដើម្បីបង្ហាញរបារកិច្ចការ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ទទួលការណែនាំកម្មវិធីដោយផ្អែកលើទម្លាប់របស់អ្នក"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"បើកការរុករកដោយប្រើចលនានៅក្នុងការកំណត់ ដើម្បីលាក់របារកិច្ចការដោយស្វ័យប្រវត្តិ"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"ធ្វើបានកាន់តែច្រើនដោយប្រើរបារកិច្ចការ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"បន្ទាប់"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ថយក្រោយ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"របាររុករក"</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_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>
</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index e63c762..5beb0d0 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ಮುಕ್ತಸ್ವರೂಪ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ಆ್ಯಪ್ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಹಿಂತಿರುಗಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನಿಂದ ಮೇಲೆ ಸ್ವೈಪ್ ಮಾಡಿ. ಈ ಗೆಸ್ಚರ್ ಯಾವಾಗಲೂ ನಿಮ್ಮನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಕರೆದೊಯ್ಯುತ್ತದೆ."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 ಬೆರಳುಗಳಿಂದ ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ. ಈ ಗೆಸ್ಚರ್ ಯಾವಾಗಲೂ ನಿಮ್ಮನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಕರೆದೊಯ್ಯುತ್ತದೆ."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಿ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಹೋಗಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನ ಅಂಚಿನಿಂದ ನೀವು ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ಬೆರಳನ್ನು ಮೇಲೆತ್ತುವ ಮೊದಲು ವಿಂಡೋವನ್ನು ಹೆಚ್ಚು ಸಮಯ ಹಿಡಿದಿಡಲು ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ನೀವು ನೇರವಾಗಿ ಸ್ವೈಪ್ ಮಾಡಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ, ನಂತರ ವಿರಾಮಗೊಳಿಸಿ."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ಚೆನ್ನಾಗಿದೆ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ಟ್ಯುಟೋರಿಯಲ್ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"ಎಲ್ಲವೂ ಸಿದ್ಧವಾಗಿದೆ!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಲು ಮೇಲೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ನಿಮ್ಮ ಮುಖಪುಟದ ಪರದೆಗೆ ಹೋಗಲು ಮುಖಪುಟ ಬಟನ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಬಳಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ನೀವು ಸಿದ್ಧರಾಗಿರುವಿರಿ"</string>
<string name="default_device_name" msgid="6660656727127422487">"ಸಾಧನ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
<string name="action_split" msgid="2098009717623550676">"ವಿಭಜಿಸಿ"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"\"ಪರದೆ ಬೇರ್ಪಡಿಸಿ\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ನ್ಯಾವಿಗೇಶನ್ ಟ್ಯುಟೋರಿಯಲ್ ಸ್ಕಿಪ್ ಮಾಡಬೇಕೇ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಕಾಣಿಸಿಕೊಂಡಿದೆ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಮುಚ್ಚಿದೆ"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ಒಂದೇ ಬಾರಿಗೆ 2 ಆ್ಯಪ್ಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್ ಅನ್ನು ಬದಿಗೆ ಎಳೆಯಿರಿ"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ಟಾಸ್ಕ್ಬಾರ್ ಅನ್ನು ತೋರಿಸಲು ನಿಧಾನವಾಗಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ನಿಮ್ಮ ದಿನಚರಿಯ ಆಧಾರದ ಮೇಲೆ ಆ್ಯಪ್ ಸಲಹೆಗಳನ್ನು ಪಡೆಯಿರಿ"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"ಟಾಸ್ಕ್ಬಾರ್ ಅನ್ನು ಸ್ವಯಂ-ಮರೆಮಾಡಲು ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಗೆಸ್ಚರ್ ನ್ಯಾವಿಗೇಶನ್ ಅನ್ನು ಆನ್ ಮಾಡಿ"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"ಟಾಸ್ಕ್ಬಾರ್ ಮೂಲಕ ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ಮುಂದೆ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ಹಿಂದೆ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</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{ಇನ್ನೂ # ಆ್ಯಪ್ ಅನ್ನು ತೋರಿಸಿ.}one{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index bf262f1..2d463d9 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"고정"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"자유 형식"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"최근 항목이 없습니다."</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"앱 사용 설정"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"모두 삭제"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"최근 앱"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"스와이프하여 홈으로 이동"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"화면 하단에서 위로 스와이프합니다. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"두 손가락을 사용해 화면 하단에서 위로 스와이프하세요. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"홈으로 이동"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"언제든지 화면을 아래에서 위로 스와이프하여 홈 화면으로 이동할 수 있습니다"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"화면 하단 가장자리에서 위로 스와이프하세요."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"창을 더 오래 누르고 있다가 손가락을 떼 보세요."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"위로 곧게 스와이프한 후 잠시 멈추세요."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"잘하셨습니다"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"튜토리얼 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"설정 완료"</string>
- <string name="allset_hint" msgid="2384632994739392447">"위로 스와이프하여 홈으로 이동"</string>
+ <string name="allset_hint" msgid="459504134589971527">"위로 스와이프하여 홈으로 이동"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"홈 화면으로 이동하려면 홈 버튼을 탭하세요."</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> 기기를 사용할 준비가 되었습니다."</string>
<string name="default_device_name" msgid="6660656727127422487">"기기"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"공유"</string>
<string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
<string name="action_split" msgid="2098009717623550676">"분할"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"다른 앱을 탭하여 화면 분할 사용"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"이 작업은 앱 또는 조직에서 허용되지 않습니다."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"이동 방법 튜토리얼을 건너뛰시겠습니까?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"작업 표시줄 튜토리얼 패널 표시됨"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"작업 표시줄 튜토리얼 패널 닫힘"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"앱을 옆으로 드래그하여 앱 2개를 동시에 사용합니다."</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"위로 천천히 스와이프하면 태스크 바가 표시됩니다."</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"루틴에 따라 앱 제안을 받습니다."</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"태스크 바를 자동 숨김하려면 설정에서 동작 탐색을 켜세요."</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"태스크 바 최대한 활용하기"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"다음"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"뒤로"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"탐색 메뉴"</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_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>
</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 82b4d60..b3ebffb 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Эркин форма режими"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Колдонмону пайдалануу параметрлери"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Баарын тазалоо"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Акыркы колдонмолор"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Башкы бетке өтүү үчүн сүрүп коюңуз"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Экранды ылдый жагынан өйдө сүрүңүз. Бул жаңсоо сизди ар дайым Башкы экранга алып барат."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Экранды ылдый жагынан өйдө 2 манжаңыз менен сүрүңүз. Бул жаңсоо ар дайым Башкы экранга алып барат."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Башкы бетке өтүү"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Каалаган убакта башкы экранга өтүү үчүн экранды ылдыйдан жогору карай сүрүңүз"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Экранды ылдыйдан өйдө сүрүңүз."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Манжаңызды алуудан мурун экранда узагыраак кармаңыз."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Экранды өйдө карай сүрүп, токтоп туруңуз."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Сонун!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Үйрөткүч: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Бүттү!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Башкы бетке өтүү үчүн экранды өйдө сүрүңүз"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Башкы бетке өтүү үчүн экранды өйдө сүрүңүз"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Башкы экранга өтүү үчүн башкы бет баскычын таптап коюңуз"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүн колдоно берсеңиз болот"</string>
<string name="default_device_name" msgid="6660656727127422487">"түзмөк"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Бөлүү"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Жаңсоолор үйрөткүчүн өткөрүп жибересизби?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапшырмалар тактасынын окутуу панели көрсөтүлдү"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Тапшырмалар тактасынын окутуу панели жабылды"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 колдонмону бир убакта пайдалануу үчүн капталга сүйрөңүз"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Тапшырмалар панелин көрүү үчүн экранды жай өйдө сүрүңүз"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Программаңыздын негизинде сунушталган колдонмолорду алуу"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Тапшырмалар панелин автоматтык түрдө жашыруу үчүн Тууралоодон жаңсап чабыттоону күйгүзүңүз"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Тапшырмалар панели менен көбүрөөк нерселерди аткарыңыз"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Кийинки"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Артка"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Чабыттоо тилкеси"</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_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>
</resources>
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index 30983c4..ee594c8 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -82,4 +82,6 @@
<dimen name="taskbar_suw_frame">96dp</dimen>
<dimen name="taskbar_suw_insets">24dp</dimen>
-</resources>
\ No newline at end of file
+ <dimen name="keyboard_quick_switch_taskview_width">205dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_height">119dp</dimen>
+</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 5a73c32..0e7af50 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ຮູບແບບອິດສະຫລະ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ການຕັ້ງຄ່າການນຳໃຊ້ແອັບ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ລຶບລ້າງທັງໝົດ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ແອັບຫຼ້າສຸດ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ປັດເພື່ອໄປໜ້າຫຼັກ"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ປັດຂຶ້ນມາຈາກລຸ່ມສຸດຂອງໜ້າຈໍທ່ານ. ທ່າທາງນີ້ຈະພາທ່ານໄປໂຮມສະກຣີນສະເໝີ."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"ປັດຂຶ້ນດ້ວຍ 2 ນິ້ວຈາກລຸ່ມສຸດຂອງໜ້າຈໍ. ທ່າທາງນີ້ຈະພາທ່ານໄປໂຮມສະກຣີນສະເໝີ."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ໄປໜ້າຫຼັກ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍຂອງທ່ານເພື່ອກັບໄປໂຮມສະກຣີນຂອງທ່ານໄດ້ທຸກເວລາ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ກະລຸນາກວດສອບວ່າທ່ານປັດຂຶ້ນຈາກຂອບລຸ່ມສຸດຂອງໜ້າຈໍ."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ລອງກົດໃສ່ໜ້າຈໍຄ້າງໄວ້ດົນຂຶ້ນກ່ອນປ່ອຍນິ້ວ."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ກະລຸນາກວດສອບວ່າທ່ານປັດຂຶ້ນຊື່ໆ, ຈາກນັ້ນຢຸດຊົ່ວຄາວ."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ດີ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ການສອນການນຳໃຊ້ທີ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"ຮຽບຮ້ອຍໝົດແລ້ວ!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ປັດຂຶ້ນເພື່ອໄປຫາໜ້າຫຼັກ"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ປັດຂຶ້ນເພື່ອໄປຫາໜ້າຫຼັກ"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ແຕະປຸ່ມໜ້າທຳອິດເພື່ອໄປຫາໂຮມສະກຣີນຂອງທ່ານ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"ທ່ານເລີ່ມໃຊ້ແທັບເລັດ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້ແລ້ວ"</string>
<string name="default_device_name" msgid="6660656727127422487">"ອຸປະກອນ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"ແບ່ງປັນ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ຮູບໜ້າຈໍ"</string>
<string name="action_split" msgid="2098009717623550676">"ແບ່ງ"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"ແຕະແອັບອື່ນເພື່ອໃຊ້ໜ້າຈໍແຍກ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ຂ້າມການສອນການນຳໃຊ້ການນຳທາງບໍ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ສະແດງການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ປິດການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ລາກແອັບໄປດ້ານຂ້າງເພື່ອໃຊ້ 2 ແອັບໃນເວລາດຽວກັນ"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ປັດຂຶ້ນຊ້າໆເພື່ອສະແດງແຖບໜ້າວຽກ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ຮັບການແນະນຳແອັບໂດຍອີງໃສ່ສິ່ງທີ່ເຮັດປະຈຳຂອງທ່ານ"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"ເປີດການນຳທາງແບບທ່າທາງໃນການຕັ້ງຄ່າເພື່ອເຊື່ອງແຖບໜ້າວຽກໄວ້ໂດຍອັດຕະໂນມັດ"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"ເຮັດສິ່ງຕ່າງໆໄດ້ຫຼາຍຂຶ້ນດ້ວຍແຖບໜ້າວຽກ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ຕໍ່ໄປ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ກັບຄືນ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ແຖບການນຳທາງ"</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_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>
</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 3dbba08..6db6b03 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Naujausios programos"</string>
@@ -78,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Šaunu!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Mokymo programa: <xliff:g id="CURRENT">%1$d</xliff:g> iš <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Paruošta!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Perbraukite aukštyn, kad grįžtumėte į pagrindinį ekraną"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Perbraukite aukštyn, kad grįžtumėte į pagrindinį ekraną"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Norėdami eiti į pagrindinį ekraną, palieskite pagrindinio ekrano mygtuką"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Esate pasirengę pradėti naudoti <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"įrenginys"</string>
@@ -86,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Bendrinti"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekrano kopija"</string>
<string name="action_split" msgid="2098009717623550676">"Išskaidymo režimas"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Išskaidyto ekrano režimas palietus kitą programą"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Išskaidyto ekrano režimą naudokite kita programa"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Jūsų organizacijoje arba naudojant šią programą neleidžiama atlikti šio veiksmo"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Praleisti naršymo mokymo programą?"</string>
@@ -118,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naršymo juosta"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rodyti dar # programą.}one{Rodyti dar # programą.}few{Rodyti dar # programas.}many{Rodyti dar # programos.}other{Rodyti dar # programų.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string>
</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 00e59ba..540a084 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Brīva forma"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Lietotņu izmantošanas iestatījumi"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Notīrīt visu"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Pēdējās izmantotās lietotnes"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Vilkšana, lai pārietu uz sākumu"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Velciet augšup no ekrāna apakšdaļas. Ar šo žestu vienmēr varat atvērt sākuma ekrānu."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Ar 2 pirkstiem velciet augšup no ekrāna apakšdaļas. Ar šo žestu vienmēr varat atvērt sākuma ekrānu."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Došanās uz sākuma ekrānu"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Jebkurā laikā varat doties uz sākuma ekrānu, no ekrāna apakšdaļas velkot augšup."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Jāvelk augšup no ekrāna apakšmalas."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Mēģiniet ilgāk turēt logu, pirms atlaižat."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Jāvelk tieši uz augšu un pēc tam jāaptur kustība."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Lieliski!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"<xliff:g id="CURRENT">%1$d</xliff:g>. mācību darbība no <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Gatavs!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Velciet augšup, lai pārietu uz sākuma ekrānu."</string>
+ <string name="allset_hint" msgid="459504134589971527">"Velciet augšup, lai pārietu uz sākuma ekrānu"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Pieskarieties pogai Sākums, lai dotos uz sākuma ekrānu"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Varat sākt izmantot savu ierīci (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
<string name="default_device_name" msgid="6660656727127422487">"ierīce"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Kopīgot"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Veikt ekrānuzņēmumu"</string>
<string name="action_split" msgid="2098009717623550676">"Sadalīt"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Lai sadalītu ekrānu, pieskarieties citai lietotnei"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Lietotne vai jūsu organizācija neatļauj veikt šo darbību."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vai izlaist navigācijas mācības?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tika atvērta uzdevumjoslas apmācība"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tika aizvērta uzdevumjoslas apmācība"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Velciet lietotni sānis, lai izmantotu 2 lietotnes vienlaikus"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Lai skatītu Uzdevumu joslu, lēni velciet augšup."</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Skatiet ieteiktās lietotnes, balstoties uz jūsu ieradumiem"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Lai Uzdevumu josla tiktu automātiski paslēpta, iestatījumos ieslēdziet žestu navigāciju."</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Plašākas iespējas, izmantojot uzdevumu joslu"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Tālāk"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atpakaļ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigācijas josla"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rādīt vēl # lietotni}zero{Rādīt vēl # lietotnes}one{Rādīt vēl # lietotni}other{Rādīt vēl # lietotnes}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string>
</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index b111c0a..588d333 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Поставки за користење на апликациите"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Избриши ги сите"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Неодамнешни апликации"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Повлечете за да одите на почетниот екран"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Повлечете нагоре од долниот раб на екранот. Ова движење секогаш ќе ве одведе на почетниот екран."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Повлечете нагоре со два прста од долниот раб на екранот. Движењево секогаш ве носи на почетниот екран."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Одете на почетниот екран"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"За да одите на вашиот почетен екран во кое било време, повлечете нагоре од дното на екранот"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Повлечете нагоре од долниот раб на екранот."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Задржете го прозорецот подолго пред да го пуштите."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Повлечете право нагоре, а потоа застанете."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Одлично!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Упатство <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Готово!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Повлечете нагоре за да појдете на почетниот екран"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Повлечете нагоре за да појдете на почетен екран"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Допрете го копчето за почетен екран за да одите на почетниот екран"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Подготвени сте да почнете да го користите вашиот <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"уред"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Сподели"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string>
<string name="action_split" msgid="2098009717623550676">"Раздели"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Допрете друга аплик. за да користите поделен екран"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Изберете друга апликација за да користите поделен екран"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Да се прескокне упатството за навигација?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигација"</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{Прикажи уште # апликација.}one{Прикажи уште # апликација.}other{Прикажи уште # апликации.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 29a7129..08b166f 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ഫ്രീഫോം"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ആപ്പ് ഉപയോഗ ക്രമീകരണം"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്ക്കുക"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"സമീപകാല ആപ്പുകൾ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ഹോമിലേക്ക് പോകാൻ സ്വെെപ്പ് ചെയ്യുക"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യൂ. ഈ ജെസ്ച്ചർ എപ്പോഴും ഹോം സ്ക്രീനിലേക്ക് നയിക്കുന്നു."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് 2 വിരലുകൾ കൊണ്ട് സ്വൈപ്പ് ചെയ്യൂ. ഈ ജെസ്ച്ചർ എല്ലായ്പ്പോഴും ഹോം സ്ക്രീനിലേക്ക് നയിക്കുന്നു."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ഹോമിലേക്ക് പോകൂ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ഏതുസമയത്തും ഹോം സ്ക്രീനിലേക്ക് പോകാൻ, സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യൂ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"സ്ക്രീനിന്റെ താഴത്തെ അരികിൽ നിന്ന് മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"റിലീസ് ചെയ്യുന്നതിന് മുമ്പ് വിൻഡോ കൂടുതൽ സമയം ഹോൾഡ് ചെയ്യാൻ ശ്രമിക്കുക."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"നേരെ മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്ത് അൽപ്പസമയം പിടിച്ചുനിർത്തുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"കൊള്ളാം!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ട്യൂട്ടോറിയൽ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"എല്ലാം സജ്ജീകരിച്ചു!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ഹോമിലേക്ക് പോകാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ഹോമിലേക്ക് പോകാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"നിങ്ങളുടെ ഹോം സ്ക്രീനിലേക്ക് പോകാൻ ഹോം ബട്ടൺ ടാപ്പ് ചെയ്യുക"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"നിങ്ങൾക്ക് <xliff:g id="DEVICE">%1$s</xliff:g> ഉപയോഗിച്ചു തുടങ്ങാം"</string>
<string name="default_device_name" msgid="6660656727127422487">"ഉപകരണം"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"പങ്കിടുക"</string>
<string name="action_screenshot" msgid="8171125848358142917">"സ്ക്രീൻഷോട്ട്"</string>
<string name="action_split" msgid="2098009717623550676">"വിഭജിക്കുക"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"സ്പ്ലിറ്റ് സ്ക്രീനിനായി മറ്റൊരു ആപ്പ് ടാപ്പുചെയ്യൂ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"സ്ക്രീൻ വിഭജന മോഡിന് മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"നാവിഗേഷൻ ട്യൂട്ടോറിയൽ ഒഴിവാക്കണോ?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"നാവിഗേഷൻ ബാർ"</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_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>
</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 9423935..cbf6b77 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бэхлэх"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Чөлөөтэй хувьсах"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Апп ашиглалтын тохиргоо"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Бүгдийг устгах"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Саяхны аппууд"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Нүүр лүү очихын тулд шудрах"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Дэлгэцийнхээ доороос дээш шударна уу. Энэ зангаа таныг тогтмол Үндсэн нүүрэнд аваачна."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 хуруугаараа дэлгэцийн доороос дээш шударна уу. Энэ зангаа таныг тогтмол Үндсэн нүүрэнд аваачна."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Үндсэн нүүр лүү очих"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Үндсэн нүүр лүүгээ хүссэн үедээ очихын тулд дэлгэцийн доороос дээш шударна уу"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Та дэлгэцийн доод булангаас дээш шударна уу."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Суллахаасаа өмнө цонхыг илүү удаан дарж үзнэ үү."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Та чигээрээ шударч, дараа нь түр зогсооно уу."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Янзтай!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"<xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g> практик хичээл"</string>
<string name="allset_title" msgid="5021126669778966707">"Тохируулж дууслаа!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Нүүр хуудас руу очихын тулд дээш шударна уу"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Нүүр хуудас руу очихын тулд дээш шударна уу"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Үндсэн нүүр лүүгээ очихын тулд нүүр хуудасны товчлуурыг товшино уу"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Та <xliff:g id="DEVICE">%1$s</xliff:g>-г ашиглаж эхлэхэд бэлэн боллоо"</string>
<string name="default_device_name" msgid="6660656727127422487">"төхөөрөмж"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Хуваалцах"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
<string name="action_split" msgid="2098009717623550676">"Хуваах"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Дэлгэцийг хуваахыг ашиглахын тулд өөр аппыг товш"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Дэлгэцийг хуваах горим ашиглах өөр апп сонгоно уу"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Навигацын практик хичээлийг алгасах уу?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигацын самбар"</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_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>
</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 2b89b6b..edd6024 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रीफॉर्म"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अॅप वापर सेटिंग्ज"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"अलीकडील अॅप्स"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"होमवर जाण्यासाठी स्वाइप करा"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"तुमच्या स्क्रीनच्या तळाकडून वर स्वाइप करा. हे जेश्चर तुम्हाला नेहमी होम स्क्रीनवर घेऊन जाते."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"स्क्रीनच्या तळापासून दोन बोटांनी वर स्वाइप करा. हे जेश्चर तुम्हाला नेहमी होम स्क्रीनवर घेऊन जाते."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"होमवर जा"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"कधीही तुमच्या होम स्क्रीनवर जाण्यासाठी, तुमच्या स्क्रीनच्या तळापासून वर स्वाइप करा"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"तुम्ही स्क्रीनच्या तळाच्या कडेपासून वर स्वाइप करत आहात याची खात्री करा."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"विंडोवरून बोट उचलण्यापूर्वी थोडा वेळ ते तेथेच धरून ठेवा."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"तुम्ही सरळ वर स्वाइप करून, त्यानंतर बोट थांबवत आहात याची खात्री करा."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"छान!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ट्यूटोरियल <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"सर्व तयार आहे!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"होम वर जाण्यासाठी वरती स्वाइप करा"</string>
+ <string name="allset_hint" msgid="459504134589971527">"होमवर जाण्यासाठी वरती स्वाइप करा"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"तुमच्या होम स्क्रीनवर जाण्यासाठी होम बटणावर टॅप करा"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"तुम्ही तुमचे <xliff:g id="DEVICE">%1$s</xliff:g> वापरण्यास सुरुवात करू शकता"</string>
<string name="default_device_name" msgid="6660656727127422487">"डिव्हाइस"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"शेअर करा"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"अॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेव्हिगेशन ट्यूटोरियल वगळायचे आहे का?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबारशी संबंधित माहिती देणारे पॅनल उघडले आहे"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबारशी संबंधित माहिती देणारे पॅनल बंद केले आहे"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"दोन ॲप्स एकत्र वापरण्यासाठी एक अॅप बाजूला ड्रॅग करा"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"टास्कबार दाखवण्यासाठी थोडे हळू वरती स्वाइप करा"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"तुमच्या दिनक्रमावर आधारित ॲप सूचना मिळवा"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"टास्कबार ऑटो हाइड करण्यासाठी सेटिंग्ज मधून जेश्चर नेव्हिगेशन सुरू करा"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार चा पुरेपूर वापर करा"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"पुढे"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"मागे जा"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेव्हिगेशन बार"</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_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>
</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 1cd50a4..72a831a 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk bebas"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apl terbaharu"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Leret untuk kembali ke laman utama"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Leret ke atas dari bahagian bawah skrin. Gerak isyarat ini sentiasa membawa anda ke Skrin utama."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Leret ke atas dengan 2 jari dari bawah skrin. Gerak isyarat ini sentiasa bawa anda ke Skrin utama."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Pergi ke laman utama"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Untuk pergi ke skrin utama anda pada bila-bila masa, leret ke atas dari bahagian bawah skrin anda"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pastikan anda meleret ke atas dari tepi sebelah bawah skrin."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Cuba tahan tetingkap untuk tempoh yang lebih lama sebelum melepaskan."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pastikan anda meleret ke atas, kemudian menjeda."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bagus!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Siap!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Leret ke atas untuk kembali ke Laman Utama"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Leret ke atas untuk mencapai laman utama"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Ketik butang skrin utama untuk pergi ke skrin utama anda"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Anda sudah sedia untuk mula menggunakan <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
<string name="default_device_name" msgid="6660656727127422487">"peranti"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Kongsi"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Tangkapan skrin"</string>
<string name="action_split" msgid="2098009717623550676">"Pisah"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Ketik apl lain untuk menggunakan skrin pisah"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih apl lain untuk menggunakan skrin pisah"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Langkau tutorial navigasi?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bar navigasi"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tunjukkan # lagi apl.}other{Tunjukkan # lagi apl.}}"</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>
</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index eb411e6..6c01fba 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးရန်"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"အလွတ်ပုံစံ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးရှင်းရန်"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"လတ်တလောသုံး အက်ပ်များ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ပင်မစာမျက်နှာသို့သွားရန် ပွတ်ဆွဲပါ"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"သင့်ဖန်သားပြင် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ။ ဤလက်ဟန်ဖြင့် ပင်မစာမျက်နှာသို့ အမြဲပြန်သွားနိုင်သည်။"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"ဖန်သားပြင်အောက်မှ အပေါ်သို့ လက် ၂ ချောင်းဖြင့် ပွတ်ဆွဲပါ။ ဤလက်ဟန်က ပင်မစာမျက်နှာသို့ အမြဲပို့ပေးမည်။"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ပင်မစာမျက်နှာသို့ သွားပါ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ပင်မစာမျက်နှာသို့ အချိန်မရွေး ပြန်သွားရန် စခရင်အောက်ခြေမှ အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ဖန်သားပြင် အောက်ခြေအစွန်မှ အပေါ်သို့ ပွတ်ဆွဲကြောင်း သေချာပါစေ။"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"မလွှတ်ခင် ဝင်းဒိုးကို အချိန်ကြာကြာ ဖိထားကြည့်ပါ။"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"အပေါ်တည့်တည့်သို့ ပွတ်ဆွဲပြီးနောက် ခဏရပ်ကြောင်း သေချာပါစေ။"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ကောင်းသည်။"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ရှင်းလင်းပို့ချချက် <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"အားလုံး အဆင်သင့်ပါ။"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ပင်မစာမျက်နှာသို့သွားရန် အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ပင်မစာမျက်နှာသို့သွားရန် အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ပင်မစာမျက်နှာသို့ သွားရန် ပင်မခလုတ်ကို တို့ပါ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> ကို စသုံးရန် အသင့်ဖြစ်ပါပြီ"</string>
<string name="default_device_name" msgid="6660656727127422487">"စက်"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
<string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"မျက်နှာပြင်ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"လမ်းညွှန်ခြင်း ရှင်းလင်းပို့ချချက်ကို ကျော်မလား။"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ပညာရေး လုပ်ဆောင်စရာဘား ပြထားသည်"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ပညာရေး လုပ်ဆောင်စရာဘား ပိတ်ထားသည်"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"အက်ပ် ၂ ခုကို တစ်ပြိုက်တည်းသုံးရန် အက်ပ်ကို ဘေးသို့ ဖိဆွဲပါ"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Taskbar ပြရန် အပေါ်သို့ ဖြည်းဖြည်းပွတ်ဆွဲပါ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ပုံမှန်အစီအစဉ်ပေါ် အခြေခံ၍ အက်ပ်အကြံပြုချက်များကို ရယူပါ"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Taskbar ကို အော်တိုဝှက်ရန် ဆက်တင်များတွင် လက်ဟန်ဖြင့်လမ်းညွှန်ခြင်း ဖွင့်နိုင်သည်"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Taskbar ဖြင့် ပိုမိုလုပ်ဆောင်နိုင်ခြင်း"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ရှေ့သို့"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"နောက်သို့"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"လမ်းညွှန်ဘား"</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_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>
</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index d49318d..cdfc476 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nylige apper"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Sveip for å gå til startskjermen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Sveip opp fra bunnen av skjermen. Denne bevegelsen tar deg alltid til startskjermen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Sveip opp med to fingre fra bunnen av skjermen. Denne bevegelsen tar deg alltid til startskjermen."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Gå til startskjermen"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"For å gå til startskjermen, sveip opp fra bunnen av skjermen når som helst"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Sørg for at du sveiper opp fra den nederste kanten av skjermen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prøv å holde vinduet lenger før du slipper."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Sørg for at du sveiper rett opp, og så stopper du."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bra!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Veiledning <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Alt er klart!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Sveip opp for å gå til startskjermen"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Sveip opp for å gå til startskjermen"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Trykk på hjemknappen for å gå til startskjermen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Nå kan du bruke <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"enheten"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Del"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
<string name="action_split" msgid="2098009717623550676">"Del opp"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Velg en annen app for å bruke delt skjerm"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisasjonen din tillater ikke denne handlingen"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du hoppe over navigeringsveiledningen?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Opplæringen for oppgavelinjen vises"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Opplæringen for oppgavelinjen er lukket"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Dra en app til siden for å bruke 2 apper samtidig"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Sveip langsomt opp for å vise oppgavelinjen"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appforslag som er basert på rutinene dine"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Slå på navigasjon med bevegelser i innstillingene for å skjule oppgavelinjen automatisk"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Gjør mer med oppgavelinjen"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Neste"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tilbake"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasjonsrad"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app til.}other{Vis # apper til.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index a162895..b8d952d 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सबै मेटाउनुहोस्"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हालसालैका एपहरू"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"होम स्क्रिनमा जान स्वाइप गर्नुहोस्"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्। यो इसारा प्रयोग गर्दा सधैँ होम स्क्रिन खुल्छ।"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"२ वटा औँला प्रयोग गरी स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्। यो जेस्चर प्रयोग गर्दा सधैँ होम स्क्रिन खुल्छ।"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"होम स्क्रिनमा जाने तरिका"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"जुनसुकै बेला होम स्क्रिनमा जान स्क्रिनको पुछारबाट माथितिर स्वाइप गर्नुहोस्"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्।"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"स्क्रिनबाट औँला उठाउनुअघि एपको विन्डोमा केही बेर छोइराख्नुहोस्।"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"सीधै माथितिर स्वाइप गर्नुहोस् अनि रोकिनुहोस्।"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"राम्रो!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ट्युटोरियल <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"सबै तयार भयो!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"होममा जान माथितिर स्वाइप गर्नुहोस्"</string>
+ <string name="allset_hint" msgid="459504134589971527">"होममा जान माथितिर स्वाइप गर्नुहोस्"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"आफ्नो होम स्क्रिनमा जान होम बटनमा ट्याप गर्नुहोस्"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"तपाईं अब आफ्नो <xliff:g id="DEVICE">%1$s</xliff:g> चलाउन थाल्न सक्नुहुन्छ"</string>
<string name="default_device_name" msgid="6660656727127422487">"डिभाइस"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"सेयर गर्नुहोस्"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट गर्नुहोस्"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिटस्क्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नु…"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेभिगेसन ट्युटोरियल स्किप गर्ने हो?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार एजुकेसन देखिएको छ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार एजुकेसन बन्द गरिएको छ"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"एपलाई छेउतिर ड्र्याग गरेर एकै पटक २ वटा एप चलाउनुहोस्"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"टास्कबार देखाउन माथितिर बिस्तारै स्वाइप गर्नुहोस्"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"आफ्नो रुटिनका आधारमा एपसम्बन्धी सुझावहरू प्राप्त गर्नुहोस्"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"टास्कबार स्वतः लुकाउन सेटिङमा गई इसारामार्फत गरिने नेभिगेसन अन गर्नुहोस्"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार प्रयोग गरेर अझ धेरै कार्य गर्नुहोस्"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"अर्को"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"पछाडि"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेभिगेसन बार"</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_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>
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index bd5387e..1c13ac0 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vrije vorm"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Instellingen voor app-gebruik"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Alles wissen"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recente apps"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swipe om naar het startscherm te gaan"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe omhoog vanaf de onderkant van het scherm. Met dit gebaar ga je altijd naar het startscherm."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swipe met 2 vingers omhoog vanaf de onderkant van het scherm. Met dit gebaar ga je altijd naar het startscherm."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Naar het startscherm"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Ga op elk moment naar je startscherm door omhoog te swipen vanaf de onderkant van je scherm"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Swipe vanaf de onderrand van het scherm omhoog."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Houd het venster langer vast voordat je loslaat."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Swipe recht omhoog en pauzeer dan."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Dat gaat lekker."</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Klaar"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swipe omhoog om naar het startscherm te gaan"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swipe omhoog om naar het startscherm te gaan"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tik op de startknop om naar je startscherm te gaan"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Je bent klaar om je <xliff:g id="DEVICE">%1$s</xliff:g> te gebruiken"</string>
<string name="default_device_name" msgid="6660656727127422487">"apparaat"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Delen"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Splitsen"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op nog een app om je scherm te splitsen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies andere app om gesplitst scherm te gebruiken"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Deze actie wordt niet toegestaan door de app of je organisatie"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigatietutorial overslaan?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Uitleg van taakbalk geopend"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Uitleg van taakbalk gesloten"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Sleep een app naar de zijkant om 2 apps tegelijk te gebruiken"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Swipe kort omhoog om de Taakbalk te bekijken"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Krijg app-suggesties op basis van je routine"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Zet navigatie met gebaren aan bij Instellingen om de Taakbalk automatisch te verbergen"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Doe meer met de Taakbalk"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Terug"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatiebalk"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Nog # app tonen.}other{Nog # apps tonen.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index f4a7f18..7711b7c 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ପିନ୍"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ଫ୍ରିଫର୍ମ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"କୌଣସି ସାମ୍ପ୍ରତିକ ଆଇଟମ୍ ନାହିଁ"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ଆପ ବ୍ୟବହାର ସେଟିଂସ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ବର୍ତ୍ତମାନର ଆପ୍"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ହୋମକୁ ଯିବା ପାଇଁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ଆପଣଙ୍କ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ। ଏହି ଜେଶ୍ଚର ସର୍ବଦା ଆପଣଙ୍କୁ ହୋମ ସ୍କ୍ରିନକୁ ନେଇଥାଏ।"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2ଟି ଆଙ୍ଗୁଠିରେ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ। ଏହି ଜେଶ୍ଚର ସର୍ବଦା ଆପଣଙ୍କୁ ହୋମ ସ୍କ୍ରିନକୁ ନେଇଥାଏ।"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ହୋମକୁ ଯାଆନ୍ତୁ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ଯେ କୌଣସି ସମୟରେ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନକୁ ଯିବା ପାଇଁ ଆପଣଙ୍କ ସ୍କିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ଆପଣ ସ୍କ୍ରିନର ତଳ ଧାରରୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ୱିଣ୍ଡୋକୁ ରିଲିଜ୍ କରିବା ପୂର୍ବରୁ ଅଧିକ ସମୟ ଧରି ରଖିବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ଆପଣ ସିଧା ଉପରକୁ ସ୍ୱାଇପ୍ କରି ତା\'ପରେ ବିରତ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ବଢ଼ିଆ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ଟ୍ୟୁଟୋରିଆଲ୍ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"ସମ୍ପୂର୍ଣ୍ଣ ଭାବେ ପ୍ରସ୍ତୁତ!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ହୋମକୁ ଯିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ମୂଳପୃଷ୍ଠାକୁ ଯିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନକୁ ଯିବା ପାଇଁ ହୋମ ବଟନରେ ଟାପ କରନ୍ତୁ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"ଆପଣ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g> ବ୍ୟବହାର କରିବା ଆରମ୍ଭ କରିବାକୁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି"</string>
<string name="default_device_name" msgid="6660656727127422487">"ଡିଭାଇସ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"ସେୟାର୍ କରନ୍ତୁ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
<string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ନାଭିଗେସନ୍ ଟ୍ୟୁଟୋରିଆଲକୁ ବାଦ୍ ଦେବେ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ଦେଖାଯାଇଛି"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ବନ୍ଦ ହୋଇଯାଇଛି"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ଥରକେ 2ଟି ଆପ୍ସ ବ୍ୟବହାର କରିବା ପାଇଁ ଏକ ଆପକୁ ପାର୍ଶ୍ୱକୁ ଡ୍ରାଗ କର"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ଟାସ୍କବାର ଦେଖାଇବା ପାଇଁ ଉପରକୁ ଧୀରେ-ସ୍ୱାଇପ କରନ୍ତୁ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ଆପଣଙ୍କ ରୁଟିନ ଆଧାରରେ ଆପ ପରାମର୍ଶଗୁଡ଼ିକୁ ପାଆନ୍ତୁ"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"ଟାସ୍କବାରକୁ ସ୍ୱତଃ-ଲୁଚାଇବା ପାଇଁ ସେଟିଂସରେ ଜେଶ୍ଚର ନାଭିଗେସନକୁ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"ଟାସ୍କବାର ମାଧ୍ୟମରେ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ପରବର୍ତ୍ତୀ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ପଛକୁ ଫେରନ୍ତୁ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ନାଭିଗେସନ ବାର"</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_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>
</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index e742292..cd1a5a5 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ਫ੍ਰੀਫਾਰਮ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ਹਾਲੀਆ ਐਪਾਂ"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ। ਇਹ ਇਸ਼ਾਰਾ ਹਮੇਸ਼ਾਂ ਤੁਹਾਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲੈ ਜਾਂਦਾ ਹੈ।"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ 2 ਉਂਗਲਾਂ ਨਾਲ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ। ਇਹ ਇਸ਼ਾਰਾ ਹਮੇਸ਼ਾਂ ਤੁਹਾਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲੈ ਜਾਂਦਾ ਹੈ।"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਜਾਓ"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਜਾਣ ਲਈ, ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਕਿਨਾਰੇ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ਛੱਡਣ ਤੋਂ ਪਹਿਲਾਂ ਵਿੰਡੋ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਿੱਧੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ, ਫਿਰ ਰੋਕੋ।"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ਵਧੀਆ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ਟਿਊਟੋਰੀਅਲ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"ਪੂਰੀ ਤਰ੍ਹਾਂ ਤਿਆਰ!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਜਾਣ ਲਈ ਹੋਮ ਬਟਨ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"ਤੁਸੀਂ ਆਪਣਾ <xliff:g id="DEVICE">%1$s</xliff:g> ਵਰਤਣ ਲਈ ਤਿਆਰ ਹੋ"</string>
<string name="default_device_name" msgid="6660656727127422487">"ਡੀਵਾਈਸ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"ਸਾਂਝਾ ਕਰੋ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
<string name="action_split" msgid="2098009717623550676">"ਸਪਲਿਟ"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ਕੀ ਨੈਵੀਗੇਸ਼ਨ ਟਿਊਟੋਰੀਅਲ ਨੂੰ ਛੱਡਣਾ ਹੈ?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਦਿਖਾਇਆ ਗਿਆ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ਇੱਕ ਵਾਰ ਵਿੱਚ 2 ਐਪਾਂ ਵਰਤਣ ਲਈ, ਐਪ ਨੂੰ ਪਾਸੇ ਵੱਲ ਘਸੀਟੋ"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ ਥੋੜ੍ਹਾ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ਤੁਹਾਡੇ ਨਿਯਮਬੱਧ ਕੰਮ ਦੇ ਆਧਾਰ \'ਤੇ ਐਪ ਸੁਝਾਅ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"ਟਾਸਕਬਾਰ ਨੂੰ ਸਵੈ-ਲੁਕਾਉਣ ਲਈ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਸ਼ਾਰਾ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"ਟਾਸਕਬਾਰ ਦਾ ਹੋਰ ਲਾਹਾ ਲਓ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ਅੱਗੇ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ਪਿੱਛੇ"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ਨੈਵੀਗੇਸ਼ਨ ਵਾਲੀ ਪੱਟੀ"</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{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}one{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}other{# ਹੋਰ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 16cb416..db7c9cf 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Przypnij"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Tryb dowolny"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ustawienia użycia aplikacji"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Wyczyść wszystko"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Ostatnie aplikacje"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Przesuń palcem, aby przejść na ekran główny"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Przesuń palcem od dołu ekranu. Ten gest zawsze powoduje przejście na ekran główny."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Przesuń 2 palcami od dołu ekranu. Ten gest zawsze powoduje przejście do ekranu głównego."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Otwórz ekran główny"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Aby wyświetlić ekran główny w dowolnym momencie, przesuń od dołu do góry ekranu"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pamiętaj, aby przesuwać palcem od dolnej krawędzi ekranu."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Przytrzymaj okno dłużej, zanim podniesiesz palec."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pamiętaj, aby przesuwać palcem prosto do góry, a potem przerwać ruch."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Super!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Samouczek <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Wszystko gotowe"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Aby przejść na ekran główny, przesuń palcem w górę"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Aby przejść na stronę główną, przesuń w górę"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Kliknij przycisk ekranu głównego, aby otworzyć ekran główny"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Teraz możesz zacząć używać urządzenia <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"urządzenie"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Udostępnij"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Zrzut ekranu"</string>
<string name="action_split" msgid="2098009717623550676">"Podziel"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Kliknij drugą aplikację, aby podzielić ekran"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Wybierz drugą aplikację, aby podzielić ekran"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Pominąć samouczek nawigacji?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Wskazówki na temat paska zadań zostały wyświetlone"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Wskazówki na temat paska zadań zostały zamknięte"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Przeciągnij aplikację w bok, aby używać 2 aplikacji naraz"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Przesuń palcem krótko w górę, aby wyświetlić pasek aplikacji"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Otrzymuj sugestie aplikacji na podstawie rutyny"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Włącz nawigację przy użyciu gestów w Ustawieniach, aby automatycznie ukrywać pasek aplikacji"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Wykorzystaj potencjał paska aplikacji"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Dalej"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Wstecz"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Pasek nawigacyjny"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaż jeszcze # aplikację.}few{Pokaż jeszcze # aplikacje.}many{Pokaż jeszcze # aplikacji.}other{Pokaż jeszcze # aplikacji.}}"</string>
+ <string name="quick_switch_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>
</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 796f0b3..25a3570 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Definições de utilização de aplicações"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recentes"</string>
@@ -78,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Boa!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Deslize rapidamente para cima para aceder ao ecrã principal"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Deslize rapidamente para cima para aceder ao ecrã principal"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão página inicial para aceder ao ecrã principal"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Já pode começar a usar o seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
@@ -86,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Partilhar"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Fazer captura de ecrã"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Toque noutra app para usar o ecrã dividido"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolher outra app para usar o ecrã dividido"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Esta ação não é permitida pela app ou a sua entidade."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorar o tutorial de navegação?"</string>
@@ -118,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para a parte superior esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para a part superior direita"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 4c95e51..a6d26e4 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recentes"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Deslizar para voltar à tela inicial"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Deslize de baixo para cima na tela. Esse gesto sempre leva você para a tela inicial."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Deslize de baixo para cima na tela com dois dedos. Esse gesto sempre leva você para a tela inicial."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir para a página inicial"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Para acessar sua tela inicial a qualquer momento, deslize de baixo para cima na tela"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Deslize da borda inferior da tela para cima."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Mantenha a janela pressionada por mais tempo antes de soltar."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Deslize para cima e pare."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Muito bem!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Deslize para cima para acessar a tela inicial"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Deslize para cima para acessar a tela inicial"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para ir para a tela inicial"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Você já pode começar a usar seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartilhar"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Toque em outro app para usar a tela dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolha outro app para usar na tela dividida"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Essa ação não é permitida pelo app ou pela organização"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Pular o tutorial de navegação?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"As dicas sobre a barra de tarefas foram abertas"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"As dicas sobre a barra de tarefas foram fechadas"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arraste um app para o lado e use dois apps ao mesmo tempo"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Deslize para cima para mostrar a Barra de tarefas"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Receba sugestões de apps com base na sua rotina"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Ative a navegação por gestos nas configs. para ocultar a Barra de tarefas automaticamente"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Aproveite ainda mais a Barra de tarefas"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Próxima"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Voltar"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}one{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index adba9e0..e785d03 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixează"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formă liberă"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setări de utilizare a aplicației"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Șterge tot"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicații recente"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Glisează pentru a accesa ecranul de pornire"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Glisează în sus din partea de jos a ecranului. Cu acest gest accesezi mereu ecranul de pornire."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Glisează în sus cu două degete din partea de jos. Cu acest gest accesezi mereu ecranul de pornire."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Înapoi la ecranul de pornire"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Pentru a accesa oricând ecranul de pornire, glisează în sus din partea de jos a ecranului"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Glisează în sus dinspre marginea de jos a ecranului."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Încearcă să ții fereastra mai mult înainte s-o eliberezi."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Glisează direct în sus, apoi întrerupe."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bravo!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorialul <xliff:g id="CURRENT">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Gata!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Glisează în sus pentru a accesa ecranul de pornire"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Glisați în sus pentru a accesa pagina principală"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Atinge butonul ecran de pornire ca să accesezi ecranul de pornire"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Ești gata să folosești <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispozitivul"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Distribuie"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string>
<string name="action_split" msgid="2098009717623550676">"Împărțit"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Atinge altă aplicație pentru ecranul împărțit"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Alege altă aplicație pentru ecranul împărțit"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Această acțiune nu este permisă de aplicație sau de organizația ta"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Omiți tutorialul de navigare?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Panoul cu informații despre bara de activități s-a afișat"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Panoul cu informații despre bara de activități s-a închis"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Trage în lateral o aplicație ca să folosești 2 aplicații deodată"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Glisează lent în sus pentru a afișa bara de activități"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Primește sugestii de aplicații în funcție de rutina ta"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activează navigarea prin gesturi în Setări ca să ascunzi automat bara de activități"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Fă mai multe din Bara de activități"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Înainte"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Înapoi"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bară de navigare"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afișează încă # aplicație}few{Afișează încă # aplicații}other{Afișează încă # de aplicații}}"</string>
+ <string name="quick_switch_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>
</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index c67ac40..55c9b15 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закрепить"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Произвольная форма"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавние приложения"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Переход на главный экран"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Проведите вверх от нижнего края дисплея. Этот жест открывает главный экран."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Проведите двумя пальцами вверх от нижнего края экрана. Этот жест открывает главный экран."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Переход на главный экран"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Чтобы открыть главный экран, проведите снизу вверх по экрану."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Проведите снизу вверх от самого края экрана."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Прежде чем отпускать палец, задержите его на дисплее подольше."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Проведите по экрану ровно вверх, а затем задержите палец в крайнем положении."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Отлично!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Руководство (шаг <xliff:g id="CURRENT">%1$d</xliff:g> из <xliff:g id="TOTAL">%2$d</xliff:g>)"</string>
<string name="allset_title" msgid="5021126669778966707">"Готово!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Чтобы перейти на главный экран, проведите вверх."</string>
+ <string name="allset_hint" msgid="459504134589971527">"Чтобы перейти на главный экран, проведите вверх."</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Нажмите кнопку главного экрана, чтобы открыть его."</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Теперь вы можете использовать <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
<string name="default_device_name" msgid="6660656727127422487">"устройство"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Поделиться"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Разделить"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Выберите другое приложение для разделения экрана."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Это действие заблокировано приложением или организацией."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустить руководство по жестам?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Обучение по работе с панелью задач показано"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Обучение по работе с панелью задач скрыто"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Используйте два приложения сразу, перетащив одно в сторону."</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Чтобы открыть панель задач, медленно проведите снизу вверх."</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Получайте рекомендации, основанные на ваших действиях."</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Чтобы панель задач скрывалась автоматически, включите навигацию с помощью жестов."</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Используйте все возможности панели задач"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Далее"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навигации"</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{Показать ещё # приложение}one{Показать ещё # приложение}few{Показать ещё # приложения}many{Показать ещё # приложений}other{Показать ещё # приложения}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 6b599ac..30c83df 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"අමුණන්න"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"යෙදුම් භාවිත සැකසීම්"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"සියල්ල හිස් කරන්න"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"මෑත යෙදුම්"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"මුල් පිටුවට යාමට ස්වයිප් කරන්න"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ඔබගේ තිරයේ පහළින් උඩට ස්වයිප් කරන්න.මෙම ඉංගිතය සැම විටම ඔබව මුල් තිරයට ගෙන යයි."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"තිරයේ පහළම සිට ඇඟිලි 2කින් ඉහළට ස්වයිප් කරන්න. මෙම ඉංගිතය සැම විටම ඔබව මුල් තිරයට ගෙන යයි."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"මුල් පිටුවට යන්න"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ඕනෑම වේලාවක දී ඔබේ මුල් තිරයට යාම සඳහා, ඔබේ තිරයෙහි පහළ සිට ඉහළට ස්වයිප් කරන්න"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ඔබ තිරයේ පහළ දාරයේ සිට ඉහළට ස්වයිප් කරන බව සහතික කර ගන්න."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"මුදා හැරීමට පෙර කවුළුව වැඩි වේලාවක් රඳවා තබා ගැනීමට උත්සාහ කරන්න."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ඔබ කෙලින්ම ඉහළට ස්වයිප් කර, අනතුරුව විරාම කරන බව සහතික කර ගන්න."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"කදිමයි!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"නිබන්ධනය <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"සියල්ල සූදානම්!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"මුල් පිටුවට යාමට ඉහළට ස්වයිප් කරන්න"</string>
+ <string name="allset_hint" msgid="459504134589971527">"මුල් පිටුවට යාමට ඉහළට ස්වයිප් කරන්න"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"ඔබේ මුල් තිරය වෙත යාමට මුල් පිටුව බොත්තම තට්ටු කරන්න"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"ඔබ ඔබේ <xliff:g id="DEVICE">%1$s</xliff:g> භාවිත කිරීම පටන් ගැනීමට සූදානම්"</string>
<string name="default_device_name" msgid="6660656727127422487">"උපාංගය"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"බෙදා ගන්න"</string>
<string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string>
<string name="action_split" msgid="2098009717623550676">"බෙදන්න"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"බෙදුම් තිරය භාවිතා කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"බෙදීම් තිරය භාවිතා කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"නිබන්ධනය සංචාලනය මඟ හරින්නද?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"කාර්ය තීරු අධ්යාපනය දිස් විය"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"කාර්ය තීරු අධ්යාපනය වසා ඇත"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"එකවර යෙදුම් 2ක් භාවිතා කිරීමට යෙදුමක් පැත්තට අදින්න"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"කාර්ය තීරුව පෙන්වීමට ඉහළට සෙමින් ස්වයිප් කරන්න"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ඔබේ දිනචරියාව මත පදනම්ව යෙදුම් යෝජනා ලබා ගන්න"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"කාර්ය තීරුව ස්වයංක්රීයව සැඟවීමට සැකසීම් තුළ අභින සංචලනය සක්රීය කරන්න"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"කාර්ය තීරුව සමග තවත් කරන්න"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ඊළඟ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ආපසු"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"සංචලන තීරුව"</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{තවත් # යෙදුමක් පෙන්වන්න.}one{තවත් යෙදුම් #ක් පෙන්වන්න.}other{තවත් යෙදුම් #ක් පෙන්වන්න.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 174c23b..e008a42 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedávne aplikácie"</string>
@@ -78,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Výborne!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Návod <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Hotovo"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Potiahnutím nahor prejdete na plochu"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Potiahnutím nahor prejdete na plochu"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Na plochu prejdete klepnutím na tlačidlo plochy"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> môžete začať používať"</string>
<string name="default_device_name" msgid="6660656727127422487">"zariadenie"</string>
@@ -86,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
<string name="action_split" msgid="2098009717623550676">"Rozdeliť"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Rozdelenú obrazovku spustíte klep. na inú aplik."</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Na použitie rozd. obrazovky vyberte inú aplikáciu"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Chcete preskočiť návod na navigáciu?"</string>
@@ -118,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigačný panel"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobraziť # ďalšiu aplikáciu.}few{Zobraziť # ďalšie aplikácie.}many{Show # more apps.}other{Zobraziť # ďalších aplikácií.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 67d443b..66238b2 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Prosta oblika"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavitve uporabe aplikacij"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Počisti vse"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Povlecite za pomik na začetni zaslon"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Z dna zaslona s prstom povlecite navzgor. S to potezo lahko vedno odprete začetni zaslon."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Z dvema prstoma povlecite navzgor z dna zaslona. S to potezo lahko vedno odprete začetni zaslon."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Pomik na začetni zaslon"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Za pomik na začetni zaslon lahko kadar koli povlečete navzgor z dna zaslona."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pazite, da povlečete s spodnjega roba zaslona navzgor."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Poskusite okno pridržati dalj časa, preden ga izpustite."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pazite, da povlečete naravnost navzgor in nato zaustavite prst."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Odlično!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Vadnica <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Končano"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Povlecite navzgor za začetni zaslon"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Povlecite navzgor za začetni zaslon"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Za pomik na začetni zaslon se dotaknite gumba za začetni zaslon."</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Pripravljeni ste, da začnete uporabljati <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"napravo"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Deli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Posnetek zaslona"</string>
<string name="action_split" msgid="2098009717623550676">"Razdeli"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Za razdeljeni zaslon se dotaknite še 1 aplikacije"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izberite drugo aplikacijo za uporabo razdeljenega zaslona."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ali vaša organizacija ne dovoljuje tega dejanja"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite preskočiti vadnico za krmarjenje?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Vrstica za krmarjenje"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premakni na vrh/levo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premakni na dno/desno"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaži še # aplikacijo.}one{Pokaži še # aplikacijo.}two{Pokaži še # aplikaciji.}few{Pokaži še # aplikacije.}other{Pokaži še # aplikacij.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index e389e9e..9cdff52 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formë e lirë"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cilësimet e përdorimit të aplikacionit"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikacionet e fundit"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Rrëshqit shpejt për të kaluar tek ekrani bazë"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Rrëshqit shpejt lart nga fundi i ekranit tënd. Ky gjest të dërgon gjithmonë tek ekrani bazë."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Rrëshqit shpejt lart me 2 gishta nga fundi i ekranit. Ky gjest të dërgon gjithmonë tek ekrani bazë."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Shko tek ekrani bazë"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Për të shkuar tek ekrani bazë në çdo kohë, rrëshqit shpejt lart nga fundi i ekranit"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Sigurohu që të rrëshqasësh shpejt lart nga skaji i poshtëm i ekranit."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Provo ta mbash shtypur dritaren për një kohë më të gjatë para se ta lëshosh."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Sigurohu që të rrëshqasësh shpejt drejt lart dhe më pas ndalo."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bukur!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Udhëzuesi <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Plotësisht gati!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Rrëshqit shpejt lart për të shkuar tek \"Ekrani bazë\""</string>
+ <string name="allset_hint" msgid="459504134589971527">"Rrëshqit shpejt lart për të shkuar në ekranin bazë"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Trokit te butoni \"kreu\" për të shkuar tek ekrani bazë"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Je gati që të fillosh të përdorësh <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"pajisje"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Ndaj"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Pamja e ekranit"</string>
<string name="action_split" msgid="2098009717623550676">"Ndaj"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Trokit një apl. tjetër; përdor ekranin e ndarë"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ky veprim nuk lejohet nga aplikacioni ose organizata jote"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Të kapërcehet udhëzuesi i navigimit?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukimi i shiritit të detyrave u shfaq"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukimi nga shiriti i detyrave u mbyll"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Zvarrit një aplikacion në anë për të përdorur 2 aplikacione njëherësh"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Rrëshqit lart ngadalë për të shfaqur \"Shiritin e detyrave\""</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Merr sugjerime për aplikacion bazuar në rutinën tënde"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Aktivizo navigimin me gjeste te \"Cilësimet\" për të fshehur \"Shiritin e detyrave\""</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Bëj më shumë me \"Shiritin e detyrave\""</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Para"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Pas"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Shiriti i navigimit"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Shfaq # aplikacion tjetër.}other{Shfaq # aplikacione të tjera.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 8a78959..a090988 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Подешавања коришћења апликације"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Обриши све"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавне апликације"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Превуците да бисте отишли на почетну страницу"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Превуците нагоре од дна екрана. Овај покрет вас увек води на почетни екран."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Превуците помоћу два прста нагоре од дна екрана. Овим покретом увек отварате почетни екран."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Идите на почетни екран"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Да бисте отишли на почетни екран у било ком тренутку, превуците нагоре од дна екрана."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Обавезно превуците нагоре од доње ивице екрана."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Пробајте да држите прозор дуже пре отпуштања."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Обавезно превуците право нагоре, па застаните."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Свака част!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Водич <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Готово!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Превуците нагоре да бисте отворили почетни екран"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Превуците нагоре да бисте отворили почетни екран"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисти ишли на почетни екран"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Спремни сте да почнете да користите <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"уређај"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Дели"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
<string name="action_split" msgid="2098009717623550676">"Подели"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Желите да прескочите водич за кретање?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Трака за навигацију"</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{Прикажи још # апликацију.}one{Прикажи још # апликацију.}few{Прикажи још # апликације.}other{Прикажи још # апликација.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index f17bc37..c3ce758 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Listan med de senaste åtgärderna är tom"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Inställningar för appanvändning"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Rensa alla"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Senaste apparna"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Svep för att öppna startskärmen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Svep uppåt från skärmens nederkant. Du kan alltid återgå till startskärmen med den här rörelsen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Svep uppåt med två fingrar från skärmens nederkant. Så kommer du alltid tillbaka till startskärmen."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Öppna startskärmen"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Öppna startskärmen när som helst genom att svepa uppåt från skärmens nederkant"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Se till att du sveper från nederkanten på skärmen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Testa att trycka längre på fönstret innan du släpper."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Se till att du sveper rakt uppåt och sedan pausar."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bra!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Självstudie <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Klart!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Svep uppåt för att öppna startskärmen"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Svep uppåt för att öppna startskärmen"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Tryck på hemknappen för att öppna startskärmen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Nu kan du börja använda din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"enhet"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Dela"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
<string name="action_split" msgid="2098009717623550676">"Delat"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <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_split_app_unsupported" msgid="2360229567007828914">"Välj en annan app för att använda delad skärm"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisationen tillåter inte den här åtgärden"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vill du hoppa över självstudierna?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Information om aktivitetsfältet visades"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Information om aktivitetsfältet stängdes"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Dra en app till sidan om du vill använda två appar samtidigt"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Svep långsamt uppåt för att visa aktivitetsfältet"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appförslag utifrån dina rutiner"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Slå på navigering med rörelser i Inställningar för att dölja aktivitetsfältet automatiskt"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Gör mer med aktivitetsfältet"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Nästa"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tillbaka"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeringsfält"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Visa # app till.}other{Visa # appar till.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 27dd32e..772b58a 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Programu za hivi karibuni"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Telezesha kidole ili uende kwenye skrini ya kwanza"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Telezesha kidole juu kuanzia chini ya skrini yako. Ishara hii kila wakati hukupeleka kwenye Skrini ya kwanza."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Telezesha vidole viwili kuelekea juu kuanzia sehemu ya chini ya skrini. Ishara hii kila wakati hukupeleka kwenye Skrini ya kwanza."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Nenda kwenye ukurasa wa mwanzo"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Ili uende kwenye skrini ya kwanza muda wowote, telezesha kidole juu kutoka sehemu ya chini ya skrini"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Hakikisha unatelezesha kidole juu kuanzia ukingo wa chini wa skrini."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Jaribu kushikilia dirisha kwa muda mrefu kabla ya kuachilia."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Hakikisha unatelezesha kidole kuelekea juu, kisha usimamishe."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Safi!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Mafunzo ya <xliff:g id="CURRENT">%1$d</xliff:g> kati ya <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Tayari!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Telezesha kidole juu ili uende kwenye skrini ya kwanza"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Telezesha kidole juu ili uende kwenye skrini ya kwanza"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Gusa kitufe cha ukurasa wa mwanzo ili uende kwenye skrini ya kwanza"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Uko tayari kuanza kutumia <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
<string name="default_device_name" msgid="6660656727127422487">"kifaa"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Shiriki"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Picha ya skrini"</string>
<string name="action_split" msgid="2098009717623550676">"Iliyogawanywa"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Gusa programu nyingine ili utumie kipengele cha kugawa skrini"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Kitendo hiki hakiruhusiwi na programu au shirika lako"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ungependa kuruka mafunzo ya usogezaji?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Paneli ya elimu kwenye upau wa shughuli inaonyeshwa"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Paneli ya elimu kwenye upau wa shughuli imefungwa"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Buruta programu pembeni ili utumie programu 2 kwa wakati mmoja"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Telezesha kidole juu taratibu ili uonyeshe Upauzana"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Pata mapendekezo ya programu kulingana na ratiba yako"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Washa usogezaji kwa kutumia ishara kwenye Mipangilio ili ufiche Upauzana kiotomatiki"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Kamilisha mengi kwa kutumia Upauzana huu"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Endelea"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Nyuma"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Sehemu ya viungo muhimu"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Onyesha programu # zaidi.}other{Onyesha programu # zaidi.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 1ddd74d..9b602c0 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"குறிப்பிட்ட வடிவமில்லாத பயன்முறை"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ஆப்ஸ் உபயோக அமைப்புகள்"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"எல்லாம் அழி"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"சமீபத்திய ஆப்ஸ்"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"முகப்புக்குச் செல்ல ஸ்வைப் செய்யுங்கள்"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"திரையின் கீழிருந்து மேலாக ஸ்வைப் செய்க. இந்தச் சைகை எப்போதும் முகப்புத் திரைக்கு அழைத்துச் செல்லும்."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 விரலால் திரையின் கீழிருந்து மேலாக ஸ்வைப் செய்க. இந்தச் சைகை முகப்புத் திரைக்கு அழைத்துச் செல்லும்."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"முகப்புக்குச் செல்லுதல்"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"எந்தத் திரையிலிருந்தும் முகப்புத் திரைக்குச் செல்ல திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்யுங்கள்"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"திரையின் கீழ் ஓரத்திலிருந்து மேல்நோக்கி ஸ்வைப் செய்வதை உறுதிசெய்துகொள்ளுங்கள்."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"விடுவிப்பதற்கு முன்பாக நீண்டநேரம் சாளரத்தை அழுத்திப் பிடித்திருங்கள்."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"மேல்நோக்கி நேராக ஸ்வைப் செய்தபிறகு இடைநிறுத்துவதை உறுதிசெய்துகொள்ளுங்கள்."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"அருமை!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"பயிற்சி <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"அனைத்தையும் அமைத்துவிட்டீர்கள்!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"முகப்புத் திரைக்குச் செல்ல மேல்நோக்கி ஸ்வைப் செய்யுங்கள்"</string>
+ <string name="allset_hint" msgid="459504134589971527">"முகப்புக்குச் செல்ல மேல்நோக்கி ஸ்வைப் செய்யுங்கள்"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"முகப்புத் திரைக்குச் செல்வதற்கு முகப்பு பட்டனைத் தட்டவும்"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தைப் பயன்படுத்தத் தயாராகிவிட்டீர்கள்"</string>
<string name="default_device_name" msgid="6660656727127422487">"சாதனம்"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"பகிர்"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string>
<string name="action_split" msgid="2098009717623550676">"பிரி"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தட்டவும்"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"திரைப் பிரிப்பை பயன்படுத்த வேறு ஆப்ஸை தேர்வுசெய்க"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"வழிகாட்டுதல் பயிற்சியைத் தவிர்க்கவா?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் காட்டப்படுகிறது"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் மூடப்பட்டது"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ஒரே நேரத்தில் 2 ஆப்ஸைப் பயன்படுத்தப் பக்கவாட்டில் இழுக்கவும்"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"செயல் பட்டியைக் காட்ட மேல்நோக்கி மெதுவாக ஸ்வைப் செய்யவும்"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"உங்கள் வழக்கத்திற்கேற்ப ஆப்ஸ் பரிந்துரைகளைப் பெறுவீர்கள்"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"செயல் பட்டியைத் தானாக மறைக்க அமைப்புகளில் சைகை வழிசெலுத்தலை இயக்கவும்"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"செயல் பட்டி மூலம் மேலும் பலவற்றைச் செய்யுங்கள்"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"அடுத்து"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"பின்செல்"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"வழிசெலுத்தல் பட்டி"</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_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>
</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 13fc478..e78dde1 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయి"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"సంప్రదాయేతర"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"యాప్ వినియోగ సెట్టింగ్లు"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"అన్నీ తీసివేయండి"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ఇటీవలి యాప్లు"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"మొదటి స్క్రీన్కు వెళ్లడానికి స్వైప్ చేయండి"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"స్క్రీన్ కింది నుండి పైకి స్వైప్ చేయండి. ఈ సంజ్ఞ ఎప్పుడూ మిమ్మల్ని మొదటి స్క్రీన్కు తీసుకెళ్తుంది."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"స్క్రీన్ కింది నుండి 2 వేళ్లతో పైకి స్వైప్ చేయండి. సంజ్ఞ ఎల్లప్పుడూ మొదటి స్క్రీన్కు తీసుకెళ్తుంది."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"మొదటి ట్యాబ్కు వెళ్లండి"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ఎప్పుడైనా మీ మొదటి స్క్రీన్కు వెళ్లడానికి, మీ స్క్రీన్ దిగువ భాగం నుండి పైకి స్వైప్ చేయండి"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"మీరు స్క్రీన్ దిగువ అంచు నుండి పైకి స్వయిప్ చేస్తున్నారని నిర్ధారించుకోండి."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"రిలీజ్ చేయడానికి ముందు విండోను ఎక్కువసేపు పట్టుకోడానికి ట్రై చేయండి."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"మీరు నేరుగా స్వైప్ చేశారని నిర్ధారించుకోండి, ఆపై పాజ్ చేయండి."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"పనితీరు బాగుంది!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ట్యుటోరియల్ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"అంతా సెట్ అయింది!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"మొదటి స్క్రీన్కు వెళ్లడానికి పైకి స్వైప్ చేయండి"</string>
+ <string name="allset_hint" msgid="459504134589971527">"హోమ్కు వెళ్లడానికి పైకి స్వైప్ చేయండి"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"మీ మొదటి స్క్రీన్కు వెళ్లడానికి హోమ్ బటన్ను ట్యాప్ చేయండి"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"మీరు ఇప్పుడు మీ <xliff:g id="DEVICE">%1$s</xliff:g>ను ఉపయోగించడం ప్రారంభించవచ్చు"</string>
<string name="default_device_name" msgid="6660656727127422487">"పరికరం"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"షేర్ చేయండి"</string>
<string name="action_screenshot" msgid="8171125848358142917">"స్క్రీన్షాట్"</string>
<string name="action_split" msgid="2098009717623550676">"స్ప్లిట్ చేయండి"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"మరొక యాప్ను ట్యాప్ చేసి, స్ప్లిట్ స్క్రీన్ వాడండి"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"స్ప్లిట్ స్క్రీన్ ఉపయోగానికి మరొక యాప్ ఎంచుకోండి"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ఈ చర్యను యాప్ గానీ, మీ సంస్థ గానీ అనుమతించవు"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"నావిగేషన్ ట్యుటోరియల్ను స్కిప్ చేయాలా?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ కనిపించింది"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ మూసివేయబడింది"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ఒకేసారి 2 యాప్లను ఉపయోగించడానికి యాప్ను పక్కకు లాగండి"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"టాస్క్బార్ను చూపడానికి నెమ్మదిగా పైకి స్వైప్ చేయండి"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"మీ రొటీన్ ఆధారంగా యాప్ సూచనలను పొందండి"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"టాస్క్బార్ను ఆటోమేటిక్గా దాచడానికి, సెట్టింగ్లలో సంజ్ఞ నావిగేషన్ను ఆన్ చేయండి"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"టాస్క్బార్తో మరిన్ని చేయండి"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"తర్వాత"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"వెనుకకు"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"నావిగేషన్ బార్"</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_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>
</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 3f939f7..4784735 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ปักหมุด"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"รูปแบบอิสระ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ไม่มีรายการล่าสุด"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"การตั้งค่าการใช้แอป"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ล้างทั้งหมด"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"แอปล่าสุด"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ปัดเพื่อไปที่หน้าแรก"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ปัดขึ้นจากด้านล่างของหน้าจอ ท่าทางสัมผัสนี้จะนำคุณไปที่หน้าจอหลักเสมอ"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"ใช้ 2 นิ้วปัดขึ้นจากด้านล่างของหน้าจอ ท่าทางสัมผัสนี้จะนำคุณไปที่หน้าจอหลักเสมอ"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ไปที่หน้าแรก"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"ปัดขึ้นจากด้านล่างของหน้าจอเพื่อไปที่หน้าจอหลักได้ทุกเมื่อ"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ปัดขึ้นจากขอบด้านล่างของหน้าจอ"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ลองแตะหน้าต่างค้างไว้นานขึ้นก่อนปล่อยนิ้ว"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ตรวจสอบว่าปัดขึ้นในแนวตรง แล้วหยุดชั่วคราว"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"ดีมาก"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"บทแนะนำ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"เรียบร้อยแล้ว"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ปัดขึ้นเพื่อไปที่หน้าแรก"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ปัดขึ้นเพื่อไปที่หน้าแรก"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"แตะปุ่มหน้าแรกเพื่อไปที่หน้าจอหลัก"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"คุณเริ่มใช้<xliff:g id="DEVICE">%1$s</xliff:g>ได้แล้ว"</string>
<string name="default_device_name" msgid="6660656727127422487">"อุปกรณ์"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"แชร์"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string>
<string name="action_split" msgid="2098009717623550676">"แยก"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"แตะแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"เลือกแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ข้ามบทแนะนำการนำทางไหม"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"แถบนำทาง"</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_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>
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index b06d57a..4120e88 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mga setting ng paggamit ng app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"I-clear lahat"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Mga kamakailang app"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Mag-swipe para pumunta sa home"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Mag-swipe pataas mula sa ibaba ng iyong screen. Dadalhin ka palagi ng galaw na ito sa Home screen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Mag-swipe pataas gamit ang 2 daliri mula sa ibaba ng screen. Dadalhin ka palagi nito sa Home screen."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Pumunta sa home"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Para pumunta sa iyong home screen anumang oras, mag-swipe pataas mula sa ibaba ng screen mo"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Tiyaking magsa-swipe ka pataas mula sa pinakaibaba ng screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Subukang pindutin nang mas matagal ang window bago ito bitawan."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Tiyaking magsa-swipe ka nang diretso pataas, pagkatapos ay mag-pause."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Magaling!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Handa na ang lahat!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Mag-swipe pataas para pumunta sa Home"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Mag-swipe pataas para pumunta sa home"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"I-tap ang button ng home para pumunta sa iyong home screen"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Handa mo nang simulan ang paggamit sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"device"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Ibahagi"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Mag-tap ng ibang app para gamitin ang split screen"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pumili ng ibang app para gamitin ang split screen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkilos na ito"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Laktawan ang tutorial sa pag-navigate?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Lumabas ang edukasyon sa taskbar"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Sarado ang edukasyon sa taskbar"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Mag-drag ng app sa gilid para makagamit ng 2 app nang sabay"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Mag-swipe nang mabagal pataas para ipakita ang Taskbar"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Makakuha ng mga iminumungkahing app batay sa iyong routine"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"I-on ang navigation gamit ang galaw sa Mga Setting para i-auto hide ang Taskbar"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Mas maraming magawa gamit ang Taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Susunod"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Bumalik"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Magpakita ng # pang app.}one{Magpakita ng # pang app.}other{Magpakita ng # pang app.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 640ada5..003eede 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Serbest çalışma"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Uygulama kullanım ayarları"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tümünü temizle"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Son uygulamalar"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Ana ekrana gitmek için kaydırma"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Ekranın alt kısmından yukarıya doğru kaydırın. Bu hareket sizi her zaman Ana ekrana götürür."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Ekranın alt kısmından 2 parmağınızla yukarı kaydırın. Bu hareket sizi her zaman Ana ekrana götürür."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ana sayfaya gidin"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"İstediğiniz zaman ana ekrana gitmek için ekranınızın altından yukarı doğru kaydırın"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Ekranın alt kenarından yukarı kaydırdığınızdan emin olun."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Bırakmadan önce pencereyi daha uzun süre tutmayı deneyin."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Düz bir şekilde yukarı kaydırıp ardından parmağınızı duraklattığınızdan emin olun."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Güzel!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Eğitim <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"İşlem tamam!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Ana ekrana gitmek için yukarı kaydırın"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Ana ekrana gitmek için yukarı kaydırın"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Ana ekranınıza gitmek için ana sayfa düğmesine dokunun"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızı kullanmaya hazırsınız"</string>
<string name="default_device_name" msgid="6660656727127422487">"cihaz"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Paylaş"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekran görüntüsü"</string>
<string name="action_split" msgid="2098009717623550676">"Böl"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Uygulamanız veya kuruluşunuz bu işleme izin vermiyor"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Gezinme eğitimi atlansın mı?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Görev çubuğu eğitimi görüntülendi"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Görev çubuğu eğitimi kapatıldı"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Aynı anda iki uygulama kullanmak için birini yana sürükleyin"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Görev çubuğunu göstermek için yukarı doğru yavaşça kaydırın"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Rutininize göre uygulama önerileri alın"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Görev çubuğunu otomatik olarak gizlemek için Ayarlar\'dan hareketle gezinmeyi etkinleştirin"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Görev çubuğuyla daha fazla şey yapın"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"İleri"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Geri"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Gezinme çubuğu"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# uygulama daha göster.}other{# uygulama daha göster}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index f3ba1f6..7b5922d 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закріпити"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Довільна форма"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налаштування використання додатка"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистити все"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Нещодавні додатки"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Проведіть пальцем, щоб перейти на головний екран"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Проведіть пальцем по екрану знизу вгору. Цей жест завжди повертатиме вас на головний екран."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Проведіть двома пальцями вгору від низу екрана. Цей жест завжди спрямовує вас на головний екран."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Перейти на головний екран"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Щоб будь-коли перейти на головний екран, проведіть пальцем вгору від низу екрана"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Проведіть пальцем угору від нижнього краю екрана."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Спробуйте втримувати вікно довше, перш ніж відпустити."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Проведіть пальцем вертикально вгору, а тоді зробіть паузу."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Чудово!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Навчальний посібник <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Готово."</string>
- <string name="allset_hint" msgid="2384632994739392447">"Щоб перейти на головний екран, проведіть пальцем угору"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Щоб перейти на головний екран, проведіть пальцем угору"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Натисніть кнопку головного екрана, щоб відкрити його"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Тепер ви можете користуватися цим пристроєм: <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"пристрій"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Поділитися"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string>
<string name="action_split" msgid="2098009717623550676">"Розділити"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустити посібник із навігації?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Панель завдань Education відкрито"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Панель завдань Education закрито"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Перетягніть убік, щоб використовувати 2 додатки одночасно"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Щоб відкрити панель завдань, повільно проведіть угору"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Отримуйте рекомендації додатків залежно від їх використання"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Увімкніть навігацію жестами в налаштуваннях, щоб автоматично приховувати панель завдань"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Більше можливостей завдяки панелі завдань"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Далі"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навігації"</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{Показати ще # додаток.}one{Показати ще # додаток.}few{Показати ще # додатки.}many{Показати ще # додатків.}other{Показати ще # додатка.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 4f0becf..c58b72d 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"فری فارم"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ایپ کے استعمال کی ترتیبات"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"حالیہ ایپس"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"ہوم پر جانے کے لیے سوائپ کریں"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"اپنی اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں۔ یہ اشارہ آپ کو ہمیشہ ہوم اسکرین پر لے جاتا ہے۔"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"اسکرین کے نیچے سے 2 انگلیوں سے اوپر سوائپ کریں۔ یہ اشارہ آپ کو ہمیشہ ہوم اسکرین پر لے جاتا ہے۔"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"گھر جائیں"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"کسی بھی وقت اپنی ہوم اسکرین پر جانے کے لیے، اپنی اسکرین کے نیچے سے اوپر سوائپ کریں"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"اس بات کو یقینی بنائیں کہ آپ اسکرین کے نچلے کنارے سے اوپر کی طرف سوائپ کریں۔"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"انگلی اٹھانے سے پہلے ونڈو کو زیادہ دیر تک پکڑنے کی کوشش کریں۔"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"اس بات کو یقینی بنائیں کہ آپ سیدھا اوپر کی طرف سوائپ کریں، پھر موقوف کریں۔"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"عمدہ!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"ٹیوٹوریل <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"سب کچھ تیار ہے!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"ہوم پر جانے کے لیے اوپر سوائپ کریں"</string>
+ <string name="allset_hint" msgid="459504134589971527">"ہوم پر جانے کے لیے اوپر سوائپ کریں"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"اپنی ہوم اسکرین پر جانے کے لیے ہوم بٹن پر تھپتھپائیں"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"آپ اپنے <xliff:g id="DEVICE">%1$s</xliff:g> کا استعمال شروع کرنے کے لیے تیار ہیں"</string>
<string name="default_device_name" msgid="6660656727127422487">"آلہ"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"اشتراک کریں"</string>
<string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string>
<string name="action_split" msgid="2098009717623550676">"اسپلٹ"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"نیویگیشن کا ٹیوٹوریل نظر انداز کریں؟"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نیویگیشن بار"</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_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>
</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 789b424..39949b0 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Mahkamlash"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
+ <string name="recents_empty_desktop_message" msgid="1358240150311509733">"Ish stoli elementlari topilmadi"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Yaqinda ishlatilgan ilovalar"</string>
@@ -61,10 +62,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Svayp bilan bosh ekranni ochish"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Ekranning pastidan tepaga qarab suring. Bu ishora doim Bosh ekranni ochadi."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 barmoq bilan ekranning quyidan tepasiga suring. Bu ishora har doim Bosh ekranni ochadi."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Boshiga"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Istalgan vaqtda bosh ekranga oʻtish uchun ekranning pastidan tepaga suring"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Barmoqni ekranning pastki chetidan yuqoriga suring."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Barmoqni uzishdan oldin oynani biroz bosib turing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Avval tik tepaga surib, keyin pauza qiling."</string>
@@ -80,7 +79,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Yaxshi!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Darslik: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Hammasi tayyor!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Boshiga qaytish uchun tepaga suring"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Boshiga qaytish uchun tepaga suring"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Bosh ekranga oʻtish uchun bosh ekran tugmasini bosing"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> xizmatga tayyor"</string>
<string name="default_device_name" msgid="6660656727127422487">"qurilma"</string>
@@ -88,8 +87,7 @@
<string name="action_share" msgid="2648470652637092375">"Ulashish"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skrinshot"</string>
<string name="action_split" msgid="2098009717623550676">"Ajratish"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Ekranni ikkiga ajratish uchun boshqa ilovani bosing"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ekranni ikkiga ajratish uchun boshqa ilovani tanlang"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Bu amal ilova yoki tashkilotingiz tomonidan taqiqlangan"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigatsiya darsi yopilsinmi?"</string>
@@ -120,4 +118,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatsiya paneli"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Yana # ta ilovani chiqarish}other{Yana # ta ilovani chiqarish}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index a00041c..178e6fe 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Dạng tự do"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cài đặt mức sử dụng ứng dụng"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Xóa tất cả"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Ứng dụng gần đây"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Vuốt để chuyển đến Màn hình chính"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Vuốt lên từ cuối màn hình. Cử chỉ này luôn đưa bạn đến Màn hình chính."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Vuốt 2 ngón tay lên từ cuối màn hình. Cử chỉ này luôn đưa bạn về Màn hình chính."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Chuyển đến màn hình chính"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Để chuyển đến màn hình chính bất cứ lúc nào, hãy vuốt lên từ cuối màn hình"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Hãy vuốt lên từ mép dưới cùng của màn hình."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Hãy thử giữ cửa sổ lâu hơn trước khi thả tay ra."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Hãy vuốt thẳng lên, sau đó tạm dừng."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Tuyệt vời!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Hướng dẫn <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Đã hoàn tất!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Vuốt lên để chuyển đến Màn hình chính"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Vuốt lên để chuyển đến màn hình chính"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Nhấn vào nút màn hình chính để chuyển đến màn hình chính"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Bạn có thể bắt đầu sử dụng <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"thiết bị"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
<string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Nhấn vào ứng dụng khác để chia đôi màn hình"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ứng dụng hoặc tổ chức của bạn không cho phép thực hiện hành động này"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Bỏ qua phần hướng dẫn thao tác?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Đã hiện bảng hướng dẫn trên thanh tác vụ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Đã đóng bảng hướng dẫn trên thanh tác vụ"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Kéo một ứng dụng sang bên để dùng 2 ứng dụng cùng lúc"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Từ từ vuốt lên để Thanh tác vụ xuất hiện"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Nhận ứng dụng đề xuất dựa trên quy trình của bạn"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Bật tính năng thao tác bằng cử chỉ trong phần Cài đặt để tự động ẩn Thanh tác vụ"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Làm nhiều việc hơn qua Thanh tác vụ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Tiếp theo"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Quay lại"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Thanh điều hướng"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Hiện thêm # ứng dụng.}other{Hiện thêm # ứng dụng.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 3d1b6b7..731c6c7 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由窗口"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"应用使用设置"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近用过的应用"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"上滑可转到主屏幕"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"从屏幕底部向上滑动。这个手势会一律将您转到主屏幕。"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"用两根手指从屏幕底部向上滑动,这个手势会一律使您回到主屏幕。"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"前往主屏幕"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"若要随时前往主屏幕,请从屏幕的底部向上滑动"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"请确保从屏幕底部边缘向上滑动。"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"请尝试按住窗口较长时间,然后再松开手指。"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"请确保直接向上滑动,然后停住。"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"很好!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"教程 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"大功告成!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"向上滑动即可转到主屏幕"</string>
+ <string name="allset_hint" msgid="459504134589971527">"向上滑动可转到主屏幕"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"点按主屏幕按钮即可前往主屏幕"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"您可以开始使用<xliff:g id="DEVICE">%1$s</xliff:g>了"</string>
<string name="default_device_name" msgid="6660656727127422487">"设备"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"分享"</string>
<string name="action_screenshot" msgid="8171125848358142917">"屏幕截图"</string>
<string name="action_split" msgid="2098009717623550676">"拆分"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"点按另一个应用即可使用分屏"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"另外选择一个应用才可使用分屏模式"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"该应用或您所在的单位不允许执行此操作"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要跳过导航教程吗?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"任务栏教程已显示"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"任务栏教程已关闭"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"将一个应用拖动到一侧,即可一次使用两个应用"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"缓慢向上滑动即可显示任务栏"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"根据您的日常安排获取应用建议"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"在设置中开启手势导航后,任务栏会自动隐藏"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"体验任务栏的更多功能"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"继续"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"导航栏"</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_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>
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 50abaa2..aeccfd2 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"向上滑動即可返回主畫面"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"從螢幕底部向上滑動。這個手勢在所有畫面下都可讓您返回主畫面。"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"請用 2 隻手指從螢幕底部向上滑動。這個手勢在所有畫面下都可讓您返回主畫面。"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"返回主畫面"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"只要從螢幕底部向上滑動,隨時可以返回主畫面"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"請從螢幕底部邊緣向上滑動。"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"請嘗試按住視窗更長時間,然後再放開。"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"請向上滑動,然後停住。"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"做得好!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"教學課程 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"設定完成!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"向上滑動即可前往主畫面"</string>
+ <string name="allset_hint" msgid="459504134589971527">"向上滑動即可前往主畫面"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"輕按主按鈕即可前往主畫面"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"您可以開始使用 <xliff:g id="DEVICE">%1$s</xliff:g> 了"</string>
<string name="default_device_name" msgid="6660656727127422487">"裝置"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"分享"</string>
<string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"輕按其他應用程式以使用分割螢幕"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"選擇其他應用程式才能使用分割螢幕"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"應用程式或您的機構不允許此操作"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要略過手勢操作教學課程嗎?"</string>
@@ -101,9 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"顯示咗工作列教學"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"閂咗工作列教學"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"將應用程式拖曳到一邊,即可同時使用 2 個應用程式"</string>
- <string name="taskbar_edu_stashing" msgid="5645461372669217294">"緩慢向上滑動即可讓工作列顯示在畫面上"</string>
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"慢慢向上滑動即可顯示工作列"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"根據您的日常安排提供應用程式建議"</string>
- <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"在設定中啟用手勢操作後,工作列就會自動隱藏"</string>
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"在「設定」中啟用手勢操作後,工作列就會自動隱藏"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"工作列助您事半功倍"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</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_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>
</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 4e04280..748581f 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"使用滑動手勢返回主畫面"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"從螢幕底部向上滑動,即可返回主畫面。"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"用 2 指從螢幕底部向上滑動,即可回到主畫面。"</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"返回主畫面"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"只要從螢幕底部向上滑動,隨時可以返回主畫面"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"請從螢幕底部邊緣向上滑動。"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"請按住視窗久一點,然後再放開。"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"請向上滑動,然後停住。"</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"很好!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"教學課程 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"設定完成!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"向上滑動即可前往主畫面"</string>
+ <string name="allset_hint" msgid="459504134589971527">"向上滑動即可前往主畫面"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"輕觸主畫面按鈕即可前往主畫面"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"你可以開始使用「<xliff:g id="DEVICE">%1$s</xliff:g>」了"</string>
<string name="default_device_name" msgid="6660656727127422487">"裝置"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"分享"</string>
<string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"輕觸另一個應用程式即可使用分割畫面"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"必須選擇另一個應用程式才能使用分割畫面"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"這個應用程式或貴機構不允許執行這個動作"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要略過手勢操作教學課程嗎?"</string>
@@ -120,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</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_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>
</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index bf88094..06ef5f6 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -22,6 +22,8 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
+ <!-- no translation found for recents_empty_desktop_message (1358240150311509733) -->
+ <skip />
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Izinhlelo zokusebenza zakamuva"</string>
@@ -61,10 +63,8 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swayipha ukuze uye ekhaya"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swayiphela phezulu kusuka phansi kwesikrini sakho.Lokhu kuthinta kuhlala kukusa esikrinini sasekhaya."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swayiphela phezulu ngeminwe emi-2 kusukela phansi esikrinini. Lesi senzo sihlala sikuyisa esikrinini Sasekhaya."</string>
- <!-- no translation found for home_gesture_tutorial_title (3126834347496917376) -->
- <skip />
- <!-- no translation found for home_gesture_tutorial_subtitle (8979014952569486971) -->
- <skip />
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Iya ekhasini lokuqala"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="8979014952569486971">"Ukuze uye esikrinini sakho sasekhaya noma kunini, swayiphela phezulu ukusuka phansi esikrinini sakho"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Qiniseka ukuthi uswayiphela phezulu kusuka emngceleni ophansi wesikrini."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Zama ukubamba iwindi isikhashana ngaphambi kokulidedela."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Qiniseka ukuthi uswayiphela ngqo phezulu bese uyamisa."</string>
@@ -80,7 +80,7 @@
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Kuhle!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Okokufundisa <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Konke kusethiwe!"</string>
- <string name="allset_hint" msgid="2384632994739392447">"Swayiphela phezulu ukuze uye Ekhaya"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Swayiphela phezulu ukuze uye ekhaya"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Thepha inkinobho yasekhaya ukuze uye kusikrini sasekhaya"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Usulungele ukuqala ukusebenzisa i-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string>
<string name="default_device_name" msgid="6660656727127422487">"idivayisi"</string>
@@ -88,8 +88,7 @@
<string name="action_share" msgid="2648470652637092375">"Yabelana"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Isithombe-skrini"</string>
<string name="action_split" msgid="2098009717623550676">"Hlukanisa"</string>
- <!-- no translation found for toast_split_select_app (8464310533320556058) -->
- <skip />
+ <string name="toast_split_select_app" msgid="8464310533320556058">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Lesi senzo asivunyelwanga uhlelo lokusebenza noma inhlangano yakho"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Yeqa isifundo sokuzulazula?"</string>
@@ -101,11 +100,9 @@
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Imfuno yebha yomsebenzi ivelile"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Imfundo yebha yomsebenzi ivaliwe"</string>
<string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Hudula i-app ukusebenzisa ama-app ama-2 ngesikhathi esisodwa"</string>
- <!-- no translation found for taskbar_edu_stashing (5645461372669217294) -->
- <skip />
+ <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Swayiphela phezulu kancane ukuze ubonise i-Taskbar"</string>
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Thola iziphakamiso ze-app ngokusekelwe kumjikelezo wakho"</string>
- <!-- no translation found for taskbar_edu_settings_persistent (1387372982791296151) -->
- <skip />
+ <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Vula ukufuna kokuthinta Kumasethingi ukuze ufihle ngokuzenzakalela ibha yomsebenzi"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Yenza okwengeziwe nge-Taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Okulandelayo"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Emuva"</string>
@@ -122,4 +119,6 @@
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Ibha yokufuna"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Bonisa i-app e-# ngaphezulu.}one{Bonisa ama-app angu-# ngaphezulu.}other{Bonisa ama-app angu-# ngaphezulu.}}"</string>
+ <string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index 336fb57..f1d4dab 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -19,4 +19,13 @@
<attr name="android:textSize"/>
<attr name="android:fontFamily"/>
</declare-styleable>
+
+ <!--
+ TaskView specific attributes. These attributes are used to customize a TaskView view in
+ XML files.
+ -->
+ <declare-styleable name="TaskView">
+ <!-- Border color for a keyboard quick switch task views -->
+ <attr name="borderColor" format="color" />
+ </declare-styleable>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 3846a9c..126ab7c 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -286,14 +286,18 @@
<dimen name="taskbar_back_button_left_margin_kids">48dp</dimen>
<dimen name="taskbar_home_button_left_margin_kids">48dp</dimen>
<dimen name="taskbar_icon_size_kids">32dp</dimen>
+ <dimen name="taskbar_all_apps_button_translation_x_offset">6dp</dimen>
+
<!-- Transient taskbar -->
<dimen name="transient_taskbar_size">72dp</dimen>
+ <dimen name="transient_taskbar_min_width">150dp</dimen>
<dimen name="transient_taskbar_icon_size">48dp</dimen>
<dimen name="transient_taskbar_margin">24dp</dimen>
<dimen name="transient_taskbar_shadow_blur">40dp</dimen>
<dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
<dimen name="transient_taskbar_stashed_size">32dp</dimen>
+ <dimen name="transient_taskbar_all_apps_button_translation_x_offset">4dp</dimen>
<!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
<dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
<!-- Taskbar swipe up thresholds -->
@@ -328,4 +332,16 @@
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
<!-- starting_surface_exit_animation_window_shift_length -->
<dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen>
+
+ <!-- Keyboard Quick Switch -->
+ <dimen name="keyboard_quick_switch_border_width">4dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
+ <dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
+ <dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
+ <dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
+ <dimen name="keyboard_quick_switch_view_spacing">16dp</dimen>
+ <dimen name="keyboard_quick_switch_split_view_spacing">2dp</dimen>
+ <dimen name="keyboard_quick_switch_view_radius">28dp</dimen>
+ <dimen name="keyboard_quick_switch_task_view_radius">16dp</dimen>
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index a82fee8..2b5975d 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -30,6 +30,9 @@
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">No recent items</string>
+ <!-- Recents: The empty recents desktop tile string. [CHAR LIMIT=NONE] -->
+ <string name="recents_empty_desktop_message">No desktop items</string>
+
<!-- Content description for the recent apps's accessibility option that opens its usage settings. [CHAR LIMIT=NONE] -->
<string name="accessibility_app_usage_settings">App usage settings</string>
@@ -197,7 +200,7 @@
<!-- Title of "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_title">All set!</string>
<!-- Hint string at the bottom of "All Set" page [CHAR LIMIT=NONE] -->
- <string name="allset_hint">Swipe up to go Home</string>
+ <string name="allset_hint">Swipe up to go home</string>
<!-- Hint string at the bottom of "All Set" page for button navigation [CHAR LIMIT=NONE] -->
<string name="allset_button_hint">Tap the home button to go to your home screen</string>
<!-- Description of "All Set" page on the user's device [CHAR LIMIT=NONE] -->
@@ -282,4 +285,12 @@
<string name="move_drop_target_top_or_left">Move to top/left</string>
<!-- Label for moving drop target to the bottom or right side of the screen, depending on orientation (from the Taskbar only). -->
<string name="move_drop_target_bottom_or_right">Move to bottom/right</string>
+
+ <!-- Label for quick switch tile showing how many more apps are available [CHAR LIMIT=NONE] -->
+ <string name="quick_switch_overflow">{count, plural,
+ =1{Show # more app.}
+ other{Show # more apps.}
+ }</string>
+ <!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
+ <string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
</resources>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 6119eb6..4417407 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -223,4 +223,11 @@
<item name="android:fontFamily">google-sans-text</item>
<item name="android:textSize">14sp</item>
</style>
-</resources>
\ No newline at end of file
+
+ <style name="KeyboardQuickSwitchOverview">
+ <item name="fontFamily">google-sans-text</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="lineHeight">20sp</item>
+ </style>
+</resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index b880a7e..9ff2cfc 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -112,7 +112,6 @@
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.model.data.ItemInfo;
@@ -213,9 +212,9 @@
private static final int WIDGET_CROSSFADE_DURATION_MILLIS = 125;
protected final QuickstepLauncher mLauncher;
- private final DragLayer mDragLayer;
+ protected final DragLayer mDragLayer;
- final Handler mHandler;
+ protected final Handler mHandler;
private final float mClosingWindowTransY;
private final float mMaxShadowRadius;
@@ -557,11 +556,7 @@
final boolean scrimEnabled = ENABLE_SCRIM_FOR_APP_LAUNCH.get();
if (scrimEnabled) {
- boolean useTaskbarColor = mDeviceProfile.isTaskbarPresentInApps
- && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get();
- int scrimColor = useTaskbarColor
- ? mLauncher.getResources().getColor(R.color.taskbar_background)
- : Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
+ int scrimColor = Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
int scrimColorTrans = ColorUtils.setAlphaComponent(scrimColor, 0);
int[] colors = isAppOpening
? new int[]{scrimColorTrans, scrimColor}
@@ -575,29 +570,6 @@
scrim.setDuration(CONTENT_SCRIM_DURATION);
scrim.setInterpolator(DEACCEL_1_5);
- if (useTaskbarColor) {
- // Hide the taskbar background color since it would duplicate the scrim.
- scrim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- LauncherTaskbarUIController taskbarUIController =
- mLauncher.getTaskbarUIController();
- if (taskbarUIController != null) {
- taskbarUIController.forceHideBackground(true);
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- LauncherTaskbarUIController taskbarUIController =
- mLauncher.getTaskbarUIController();
- if (taskbarUIController != null) {
- taskbarUIController.forceHideBackground(false);
- }
- }
- });
- }
-
launcherAnimator.play(scrim);
}
}
@@ -1097,32 +1069,38 @@
return;
}
if (hasControlRemoteAppTransitionPermission()) {
- mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
-
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
- definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN,
- WindowConfiguration.ACTIVITY_TYPE_STANDARD,
- new RemoteAnimationAdapter(
- new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
- false /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
-
- if (KEYGUARD_ANIMATION.get()) {
- mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
- definition.addRemoteAnimation(
- WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
- new RemoteAnimationAdapter(
- new LauncherAnimationRunner(
- mHandler, mKeyguardGoingAwayRunner,
- true /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
- }
-
+ addRemoteAnimations(definition);
mLauncher.registerRemoteAnimations(definition);
}
}
/**
+ * Adds remote animations to a {@link RemoteAnimationDefinition}. May be overridden to add
+ * additional animations.
+ */
+ protected void addRemoteAnimations(RemoteAnimationDefinition definition) {
+ mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
+ definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD,
+ new RemoteAnimationAdapter(
+ new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
+ false /* startAtFrontOfQueue */),
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+
+ if (KEYGUARD_ANIMATION.get()) {
+ mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
+ definition.addRemoteAnimation(
+ WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+ new RemoteAnimationAdapter(
+ new LauncherAnimationRunner(
+ mHandler, mKeyguardGoingAwayRunner,
+ true /* startAtFrontOfQueue */),
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ }
+ }
+
+ /**
* Registers remote animations used when closing apps to home screen.
*/
public void registerRemoteTransitions() {
@@ -1163,7 +1141,7 @@
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
}
- private void unregisterRemoteAnimations() {
+ protected void unregisterRemoteAnimations() {
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 4fbe8cf..e8f2496 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -36,7 +36,6 @@
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.AlphaUpdateListener;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusIndicatorHelper;
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
import com.android.launcher3.model.data.ItemInfo;
@@ -65,7 +64,6 @@
private FloatingHeaderView mParent;
private boolean mPredictionsEnabled = false;
- private @Nullable List<ItemInfo> mPendingPredictedItems;
private OnLongClickListener mOnIconLongClickListener = ItemLongClickListener.INSTANCE_ALL_APPS;
public PredictionRowView(@NonNull Context context) {
@@ -159,18 +157,10 @@
* we can optimize by swapping them in place.
*/
public void setPredictedApps(List<ItemInfo> items) {
- if (!FeatureFlags.ENABLE_APP_PREDICTIONS_WHILE_VISIBLE.get()
- && !mActivityContext.isBindingItems()
- && isShown()
- && getWindowVisibility() == View.VISIBLE) {
- mPendingPredictedItems = items;
- return;
- }
applyPredictedApps(items);
}
private void applyPredictedApps(List<ItemInfo> items) {
- mPendingPredictedItems = null;
mPredictedApps.clear();
mPredictedApps.addAll(items.stream()
.filter(itemInfo -> itemInfo instanceof WorkspaceItemInfo)
@@ -265,13 +255,4 @@
return getChildAt(0);
}
-
- @Override
- public void onVisibilityAggregated(boolean isVisible) {
- super.onVisibilityAggregated(isVisible);
-
- if (mPendingPredictedItems != null && !isVisible) {
- applyPredictedApps(mPendingPredictedItems);
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 0a2a9b3..5c2f6b1 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -41,7 +41,6 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.graphics.DragPreviewProvider;
@@ -279,32 +278,6 @@
* Sets or updates the predicted items
*/
public void setPredictedItems(FixedContainerItems items) {
- boolean shouldIgnoreVisibility = FeatureFlags.ENABLE_APP_PREDICTIONS_WHILE_VISIBLE.get()
- || mLauncher.isWorkspaceLoading()
- || mPredictedItems.equals(items.items)
- || mHotseat.getShortcutsAndWidgets().getChildCount() < mHotSeatItemsCount;
- if (!shouldIgnoreVisibility
- && mHotseat.isShown()
- && mHotseat.getWindowVisibility() == View.VISIBLE) {
- mHotseat.setOnVisibilityAggregatedCallback((isVisible) -> {
- if (isVisible) {
- return;
- }
- mHotseat.setOnVisibilityAggregatedCallback(null);
-
- applyPredictedItems(items);
- });
- } else {
- mHotseat.setOnVisibilityAggregatedCallback(null);
-
- applyPredictedItems(items);
- }
- }
-
- /**
- * Sets or updates the predicted items only once the hotseat becomes hidden to the user
- */
- private void applyPredictedItems(FixedContainerItems items) {
mPredictedItems = new ArrayList(items.items);
if (mPredictedItems.isEmpty()) {
HotseatRestoreHelper.restoreBackup(mLauncher);
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index ad6ce7d..2e1318b 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -112,10 +112,23 @@
}
@Override
- @WorkerThread
- public void loadItems(UserManagerState ums, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+ public void loadHotseatItems(UserManagerState ums,
+ Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
// TODO: Implement caching and preloading
- super.loadItems(ums, pinnedShortcuts);
+ super.loadHotseatItems(ums, pinnedShortcuts);
+
+ WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
+ mIDP.numDatabaseHotseatIcons, mHotseatState.containerId);
+ FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId,
+ mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get));
+ mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems);
+ }
+
+ @Override
+ public void loadAllAppsItems(UserManagerState ums,
+ Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+ // TODO: Implement caching and preloading
+ super.loadAllAppsItems(ums, pinnedShortcuts);
WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
mIDP.numDatabaseAllAppsColumns, mAllAppsState.containerId);
@@ -123,17 +136,22 @@
mAllAppsState.containerId, mAllAppsState.storage.read(mApp.getContext(),
allAppsFactory, ums.allUsers::get));
mDataModel.extraItems.put(mAllAppsState.containerId, allAppsPredictionItems);
+ }
- WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
- mIDP.numDatabaseHotseatIcons, mHotseatState.containerId);
- FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId,
- mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get));
- mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems);
+ @Override
+ public void loadWidgetsRecommendationItems() {
+ // TODO: Implement caching and preloading
+ super.loadWidgetsRecommendationItems();
// Widgets prediction isn't used frequently. And thus, it is not persisted on disk.
mDataModel.extraItems.put(mWidgetsRecommendationState.containerId,
new FixedContainerItems(mWidgetsRecommendationState.containerId,
new ArrayList<>()));
+ }
+
+ @Override
+ public void markActive() {
+ super.markActive();
mActive = true;
}
diff --git a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
index 20c8c44..2b6f77f 100644
--- a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
+++ b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
@@ -32,8 +32,8 @@
import com.android.launcher3.views.ActivityContext
/**
- * Shortcut to allow starting split. Default interaction for [onClick] is to launch
- * split selection mode
+ * Shortcut to allow starting split. Default interaction for [onClick] is to launch split selection
+ * mode
*/
abstract class SplitShortcut<T>(
iconResId: Int,
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index ae121e2..d087d39 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.statehandlers;
import android.os.SystemProperties;
+import android.util.Log;
import android.view.View;
import com.android.launcher3.Launcher;
@@ -29,6 +30,9 @@
*/
public class DesktopVisibilityController {
+ private static final String TAG = "DesktopVisController";
+ private static final boolean DEBUG = false;
+
private final Launcher mLauncher;
private boolean mFreeformTasksVisible;
@@ -58,6 +62,9 @@
* Sets whether freeform windows are visible and updates launcher visibility based on that.
*/
public void setFreeformTasksVisible(boolean freeformTasksVisible) {
+ if (DEBUG) {
+ Log.d(TAG, "setFreeformTasksVisible: visible=" + freeformTasksVisible);
+ }
if (!isDesktopModeSupported()) {
return;
}
@@ -83,6 +90,9 @@
* Sets whether the overview is visible and updates launcher visibility based on that.
*/
public void setOverviewStateEnabled(boolean overviewStateEnabled) {
+ if (DEBUG) {
+ Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled);
+ }
if (!isDesktopModeSupported()) {
return;
}
@@ -109,6 +119,9 @@
* Sets whether recents gesture is in progress.
*/
public void setGestureInProgress(boolean gestureInProgress) {
+ if (DEBUG) {
+ Log.d(TAG, "setGestureInProgress: inProgress=" + gestureInProgress);
+ }
if (!isDesktopModeSupported()) {
return;
}
@@ -118,6 +131,9 @@
}
private void setLauncherViewsVisibility(int visibility) {
+ if (DEBUG) {
+ Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility);
+ }
View workspaceView = mLauncher.getWorkspace();
if (workspaceView != null) {
workspaceView.setVisibility(visibility);
@@ -129,6 +145,9 @@
}
private void markLauncherPaused() {
+ if (DEBUG) {
+ Log.d(TAG, "markLauncherPaused");
+ }
StatefulActivity<LauncherState> activity =
QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
if (activity != null) {
@@ -137,6 +156,9 @@
}
private void markLauncherResumed() {
+ if (DEBUG) {
+ Log.d(TAG, "markLauncherResumed");
+ }
StatefulActivity<LauncherState> activity =
QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
// Check activity state before calling setResumed(). Launcher may have been actually
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 474dc3d..c165750 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
-import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
import android.animation.Animator;
@@ -44,6 +43,17 @@
getRecentsView().setTaskLaunchListener(toState == RecentsState.DEFAULT
? (() -> animateToRecentsState(RecentsState.BACKGROUND_APP)) : null);
}
+
+ @Override
+ public void onStateTransitionComplete(RecentsState finalState) {
+ boolean finalStateDefault = finalState == RecentsState.DEFAULT;
+ // TODO(b/268120202) Taskbar shows up on 3P home, currently we don't go to
+ // overview from 3P home. Either implement that or it'll change w/ contextual?
+ boolean disallowLongClick = finalState == RecentsState.OVERVIEW_SPLIT_SELECT;
+ Utilities.setOverviewDragState(mControllers,
+ finalStateDefault /*disallowGlobalDrag*/, disallowLongClick,
+ finalStateDefault /*allowInitialSplitSelection*/);
+ }
};
public FallbackTaskbarUIController(RecentsActivity recentsActivity) {
@@ -72,7 +82,8 @@
public Animator createAnimToRecentsState(RecentsState toState, long duration) {
boolean useStashedLauncherState = toState.hasOverviewActions();
boolean stashedLauncherState =
- useStashedLauncherState && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get();
+ useStashedLauncherState && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()
+ && toState == RecentsState.MODAL_TASK;
TaskbarStashController stashController = mControllers.taskbarStashController;
// Set both FLAG_IN_STASHED_LAUNCHER_STATE and FLAG_IN_APP to ensure the state is respected.
// For all other states, just use the current stashed-in-app setting (e.g. if long clicked).
@@ -82,7 +93,8 @@
}
private void animateToRecentsState(RecentsState toState) {
- Animator anim = createAnimToRecentsState(toState, TASKBAR_STASH_DURATION);
+ Animator anim = createAnimToRecentsState(toState,
+ mControllers.taskbarStashController.getStashDuration());
if (anim != null) {
anim.start();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
new file mode 100644
index 0000000..c4962cd
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.util.GroupTask;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * Handles initialization of the {@link KeyboardQuickSwitchViewController}.
+ */
+public final class KeyboardQuickSwitchController implements
+ TaskbarControllers.LoggableTaskbarController {
+
+ static final int MAX_TASKS = 6;
+
+ @NonNull private final ControllerCallbacks mControllerCallbacks = new ControllerCallbacks();
+
+ // Initialized on init
+ @Nullable private RecentsModel mModel;
+
+ // Used to keep track of the last requested task list id, so that we do not request to load the
+ // tasks again if we have already requested it and the task list has not changed
+ private int mTaskListChangeId = -1;
+ // Only empty before the recent tasks list has been loaded the first time
+ @NonNull private List<GroupTask> mTasks = new ArrayList<>();
+ private int mNumHiddenTasks = 0;
+
+ // Initialized in init
+ private TaskbarControllers mControllers;
+
+ @Nullable private KeyboardQuickSwitchViewController mQuickSwitchViewController;
+
+ /** Initialize the controller. */
+ public void init(@NonNull TaskbarControllers controllers) {
+ mControllers = controllers;
+ mModel = RecentsModel.INSTANCE.get(controllers.taskbarActivityContext);
+ }
+
+ void onConfigurationChanged(@ActivityInfo.Config int configChanges) {
+ if (mQuickSwitchViewController == null) {
+ return;
+ }
+ if ((configChanges & (ActivityInfo.CONFIG_KEYBOARD
+ | ActivityInfo.CONFIG_KEYBOARD_HIDDEN)) != 0) {
+ mQuickSwitchViewController.closeQuickSwitchView(true);
+ return;
+ }
+ int currentFocusedIndex = mQuickSwitchViewController.getCurrentFocusedIndex();
+ onDestroy();
+ if (currentFocusedIndex != -1) {
+ mControllers.taskbarActivityContext.getMainThreadHandler().post(
+ () -> openQuickSwitchView(currentFocusedIndex));
+ }
+ }
+
+ void openQuickSwitchView() {
+ openQuickSwitchView(-1);
+ }
+
+ private void openQuickSwitchView(int currentFocusedIndex) {
+ if (mQuickSwitchViewController != null) {
+ return;
+ }
+ TaskbarOverlayContext overlayContext =
+ mControllers.taskbarOverlayController.requestWindow();
+ KeyboardQuickSwitchView keyboardQuickSwitchView =
+ (KeyboardQuickSwitchView) overlayContext.getLayoutInflater()
+ .inflate(
+ R.layout.keyboard_quick_switch_view,
+ overlayContext.getDragLayer(),
+ /* attachToRoot= */ false);
+ mQuickSwitchViewController = new KeyboardQuickSwitchViewController(
+ mControllers, overlayContext, keyboardQuickSwitchView, mControllerCallbacks);
+
+ if (mModel.isTaskListValid(mTaskListChangeId)) {
+ mQuickSwitchViewController.openQuickSwitchView(
+ mTasks, mNumHiddenTasks, /* updateTasks= */ false, currentFocusedIndex);
+ return;
+ }
+ mTaskListChangeId = mModel.getTasks((tasks) -> {
+ // Only store MAX_TASK tasks, from most to least recent
+ Collections.reverse(tasks);
+ mTasks = tasks.stream().limit(MAX_TASKS).collect(Collectors.toList());
+ mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
+ mQuickSwitchViewController.openQuickSwitchView(
+ mTasks, mNumHiddenTasks, /* updateTasks= */ true, currentFocusedIndex);
+ });
+ }
+
+ void closeQuickSwitchView() {
+ if (mQuickSwitchViewController == null) {
+ return;
+ }
+ mQuickSwitchViewController.closeQuickSwitchView(true);
+ }
+
+ /**
+ * See {@link TaskbarUIController#launchFocusedTask()}
+ */
+ int launchFocusedTask() {
+ // Return -1 so that the RecentsView is not incorrectly opened when the user closes the
+ // quick switch view by tapping the screen.
+ return mQuickSwitchViewController == null
+ ? -1 : mQuickSwitchViewController.launchFocusedTask();
+ }
+
+ void onDestroy() {
+ if (mQuickSwitchViewController != null) {
+ mQuickSwitchViewController.onDestroy();
+ }
+ }
+
+ @Override
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "KeyboardQuickSwitchController:");
+
+ pw.println(prefix + "\tisOpen=" + (mQuickSwitchViewController != null));
+ pw.println(prefix + "\tmNumHiddenTasks=" + mNumHiddenTasks);
+ pw.println(prefix + "\tmTaskListChangeId=" + mTaskListChangeId);
+ pw.println(prefix + "\tmTasks=[");
+ for (GroupTask task : mTasks) {
+ Task task1 = task.task1;
+ Task task2 = task.task2;
+ ComponentName cn1 = task1.getTopComponent();
+ ComponentName cn2 = task2 != null ? task2.getTopComponent() : null;
+ pw.println(prefix + "\t\tt1: (id=" + task1.key.id
+ + "; package=" + (cn1 != null ? cn1.getPackageName() + ")" : "no package)")
+ + " t2: (id=" + (task2 != null ? task2.key.id : "-1")
+ + "; package=" + (cn2 != null ? cn2.getPackageName() + ")"
+ : "no package)"));
+ }
+ pw.println(prefix + "\t]");
+
+ if (mQuickSwitchViewController != null) {
+ mQuickSwitchViewController.dumpLogs(prefix + '\t', pw);
+ }
+ }
+
+ class ControllerCallbacks {
+
+ int getTaskCount() {
+ return mNumHiddenTasks == 0 ? mTasks.size() : MAX_TASKS + 1;
+ }
+
+ @Nullable
+ GroupTask getTaskAt(int index) {
+ return index < 0 || index >= mTasks.size() ? null : mTasks.get(index);
+ }
+
+ void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback) {
+ mModel.getThumbnailCache().updateThumbnailInBackground(task, callback);
+ }
+
+ void updateTitleInBackground(Task task, Consumer<Task> callback) {
+ mModel.getIconCache().updateIconInBackground(task, callback);
+ }
+
+ void onCloseComplete() {
+ mQuickSwitchViewController = null;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
new file mode 100644
index 0000000..84129fd
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -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.taskbar;
+
+import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
+
+import android.animation.Animator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+import com.android.quickstep.util.BorderAnimator;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.function.Consumer;
+
+/**
+ * A view that displays a recent task during a keyboard quick switch.
+ */
+public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
+
+ @NonNull private final BorderAnimator mBorderAnimator;
+
+ @Nullable private ImageView mThumbnailView1;
+ @Nullable private ImageView mThumbnailView2;
+
+ public KeyboardQuickSwitchTaskView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public KeyboardQuickSwitchTaskView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public KeyboardQuickSwitchTaskView(
+ @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public KeyboardQuickSwitchTaskView(
+ @NonNull Context context,
+ @Nullable AttributeSet attrs,
+ int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ setWillNotDraw(false);
+ Resources resources = context.getResources();
+ mBorderAnimator = new BorderAnimator(
+ /* borderBoundsBuilder= */ bounds -> bounds.set(0, 0, getWidth(), getHeight()),
+ /* borderWidthPx= */ resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width),
+ /* borderRadiusPx= */ resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_task_view_radius),
+ /* borderColor= */ attrs == null
+ ? DEFAULT_BORDER_COLOR
+ : context.getTheme()
+ .obtainStyledAttributes(
+ attrs,
+ R.styleable.TaskView,
+ defStyleAttr,
+ defStyleRes)
+ .getColor(
+ R.styleable.TaskView_borderColor,
+ DEFAULT_BORDER_COLOR),
+ /* invalidateViewCallback= */ KeyboardQuickSwitchTaskView.this::invalidate);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mThumbnailView1 = findViewById(R.id.thumbnail1);
+ mThumbnailView2 = findViewById(R.id.thumbnail2);
+ }
+
+ @NonNull
+ protected Animator getFocusAnimator(boolean focused) {
+ return mBorderAnimator.buildAnimator(focused);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ mBorderAnimator.drawBorder(canvas);
+ }
+
+ protected void setThumbnails(
+ @NonNull Task task1,
+ @Nullable Task task2,
+ @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction,
+ @Nullable TitleUpdateFunction titleUpdateFunction) {
+ applyThumbnail(mThumbnailView1, task1, thumbnailUpdateFunction);
+ applyThumbnail(mThumbnailView2, task2, thumbnailUpdateFunction);
+
+ if (titleUpdateFunction == null) {
+ setContentDescription(task2 == null
+ ? task1.titleDescription
+ : getContext().getString(
+ R.string.quick_switch_split_task,
+ task1.titleDescription,
+ task2.titleDescription));
+ return;
+ }
+ titleUpdateFunction.updateTitleInBackground(task1, t ->
+ setContentDescription(task1.titleDescription));
+ if (task2 == null) {
+ return;
+ }
+ titleUpdateFunction.updateTitleInBackground(task2, t ->
+ setContentDescription(getContext().getString(
+ R.string.quick_switch_split_task,
+ task1.titleDescription,
+ task2.titleDescription)));
+ }
+
+ private void applyThumbnail(
+ @Nullable ImageView thumbnailView,
+ @Nullable Task task,
+ @Nullable ThumbnailUpdateFunction updateFunction) {
+ if (thumbnailView == null) {
+ return;
+ }
+ if (task == null) {
+ return;
+ }
+ if (updateFunction == null) {
+ applyThumbnail(thumbnailView, task.thumbnail);
+ return;
+ }
+ updateFunction.updateThumbnailInBackground(
+ task, thumbnailData -> applyThumbnail(thumbnailView, thumbnailData));
+ }
+
+ private void applyThumbnail(
+ @NonNull ImageView thumbnailView, ThumbnailData thumbnailData) {
+ Bitmap bm = thumbnailData == null ? null : thumbnailData.thumbnail;
+
+ thumbnailView.setVisibility(VISIBLE);
+ thumbnailView.setImageBitmap(bm);
+ }
+
+ protected interface ThumbnailUpdateFunction {
+
+ void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback);
+ }
+
+ protected interface TitleUpdateFunction {
+
+ void updateTitleInBackground(Task task, Consumer<Task> callback);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
new file mode 100644
index 0000000..745defc
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID;
+
+import static com.android.launcher3.taskbar.KeyboardQuickSwitchController.MAX_TASKS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.icu.text.MessageFormat;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.Interpolators;
+import com.android.quickstep.util.GroupTask;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * View that allows quick switching between recent tasks through keyboard alt-tab and alt-shift-tab
+ * commands.
+ */
+public class KeyboardQuickSwitchView extends ConstraintLayout {
+
+ private static final long OUTLINE_ANIMATION_DURATION_MS = 333;
+ private static final float OUTLINE_START_HEIGHT_FACTOR = 0.45f;
+ private static final float OUTLINE_START_RADIUS_FACTOR = 0.25f;
+ private static final Interpolator OPEN_OUTLINE_INTERPOLATOR =
+ Interpolators.EMPHASIZED_DECELERATE;
+ private static final Interpolator CLOSE_OUTLINE_INTERPOLATOR =
+ Interpolators.EMPHASIZED_ACCELERATE;
+
+ private static final long ALPHA_ANIMATION_DURATION_MS = 83;
+ private static final long ALPHA_ANIMATION_START_DELAY_MS = 67;
+
+ private static final long CONTENT_TRANSLATION_X_ANIMATION_DURATION_MS = 500;
+ private static final long CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS = 333;
+ private static final float CONTENT_START_TRANSLATION_X_DP = 32;
+ private static final float CONTENT_START_TRANSLATION_Y_DP = 40;
+ private static final Interpolator OPEN_TRANSLATION_X_INTERPOLATOR = Interpolators.EMPHASIZED;
+ private static final Interpolator OPEN_TRANSLATION_Y_INTERPOLATOR =
+ Interpolators.EMPHASIZED_DECELERATE;
+ private static final Interpolator CLOSE_TRANSLATION_Y_INTERPOLATOR =
+ Interpolators.EMPHASIZED_ACCELERATE;
+
+ private static final long CONTENT_ALPHA_ANIMATION_DURATION_MS = 83;
+ private static final long CONTENT_ALPHA_ANIMATION_START_DELAY_MS = 83;
+
+ private final AnimatedFloat mOutlineAnimationProgress = new AnimatedFloat(
+ this::invalidateOutline);
+
+ private HorizontalScrollView mScrollView;
+ private ConstraintLayout mContent;
+
+ private int mTaskViewHeight;
+ private int mSpacing;
+ private int mOutlineRadius;
+ private boolean mIsRtl;
+
+ @Nullable private AnimatorSet mOpenAnimation;
+
+ @Nullable private KeyboardQuickSwitchViewController.ViewCallbacks mViewCallbacks;
+
+ public KeyboardQuickSwitchView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public KeyboardQuickSwitchView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public KeyboardQuickSwitchView(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public KeyboardQuickSwitchView(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mScrollView = findViewById(R.id.scroll_view);
+ mContent = findViewById(R.id.content);
+
+ Resources resources = getResources();
+ mTaskViewHeight = resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_taskview_height);
+ mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
+ mOutlineRadius = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_radius);
+ mIsRtl = Utilities.isRtl(resources);
+ }
+
+ @NonNull
+ private KeyboardQuickSwitchTaskView createAndAddTaskView(
+ int index,
+ int width,
+ boolean isFinalView,
+ boolean updateTasks,
+ @NonNull LayoutInflater layoutInflater,
+ @Nullable View previousView,
+ @NonNull List<GroupTask> groupTasks) {
+ KeyboardQuickSwitchTaskView taskView = (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
+ R.layout.keyboard_quick_switch_taskview, mContent, false);
+ taskView.setId(View.generateViewId());
+ taskView.setOnClickListener(v -> mViewCallbacks.launchTappedTask(index));
+
+ LayoutParams lp = new LayoutParams(width, mTaskViewHeight);
+ // Create a right-to-left ordering of views (or left-to-right in RTL locales)
+ if (previousView != null) {
+ lp.endToStart = previousView.getId();
+ } else {
+ lp.endToEnd = PARENT_ID;
+ }
+ lp.topToTop = PARENT_ID;
+ lp.bottomToBottom = PARENT_ID;
+ // Add spacing between views
+ lp.setMarginEnd(mSpacing);
+ if (isFinalView) {
+ // Add spacing to the start of the final view so that scrolling ends with some padding.
+ lp.startToStart = PARENT_ID;
+ lp.setMarginStart(mSpacing);
+ lp.horizontalBias = 1f;
+ }
+
+ GroupTask groupTask = groupTasks.get(index);
+ taskView.setThumbnails(
+ groupTask.task1,
+ groupTask.task2,
+ updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+ updateTasks ? mViewCallbacks::updateTitleInBackground : null);
+
+ mContent.addView(taskView, lp);
+ return taskView;
+ }
+
+ private void createAndAddOverviewButton(
+ int width,
+ @NonNull LayoutInflater layoutInflater,
+ @Nullable View previousView,
+ @NonNull String overflowString) {
+ KeyboardQuickSwitchTaskView overviewButton =
+ (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
+ R.layout.keyboard_quick_switch_overview, this, false);
+ overviewButton.setOnClickListener(v -> mViewCallbacks.launchTappedTask(MAX_TASKS));
+
+ overviewButton.<TextView>findViewById(R.id.text).setText(overflowString);
+
+ ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
+ width, mTaskViewHeight);
+ lp.startToStart = PARENT_ID;
+ lp.endToStart = previousView.getId();
+ lp.topToTop = PARENT_ID;
+ lp.bottomToBottom = PARENT_ID;
+ lp.setMarginEnd(mSpacing);
+ lp.setMarginStart(mSpacing);
+
+ mContent.addView(overviewButton, lp);
+ }
+
+ protected void applyLoadPlan(
+ @NonNull Context context,
+ @NonNull List<GroupTask> groupTasks,
+ int numHiddenTasks,
+ boolean updateTasks,
+ int currentFocusIndexOverride,
+ @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
+ if (groupTasks.isEmpty()) {
+ // Do not show the quick switch view.
+ return;
+ }
+ mViewCallbacks = viewCallbacks;
+ Resources resources = context.getResources();
+ int width = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_taskview_width);
+ View previousView = null;
+
+ LayoutInflater layoutInflater = LayoutInflater.from(context);
+ int tasksToDisplay = Math.min(MAX_TASKS, groupTasks.size());
+ for (int i = 0; i < tasksToDisplay; i++) {
+ previousView = createAndAddTaskView(
+ i,
+ width,
+ /* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
+ updateTasks,
+ layoutInflater,
+ previousView,
+ groupTasks);
+ }
+
+ if (numHiddenTasks > 0) {
+ HashMap<String, Integer> args = new HashMap<>();
+ args.put("count", numHiddenTasks);
+ createAndAddOverviewButton(
+ width,
+ layoutInflater,
+ previousView,
+ new MessageFormat(
+ resources.getString(R.string.quick_switch_overflow),
+ Locale.getDefault()).format(args));
+ }
+
+ getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ animateOpen(currentFocusIndexOverride);
+
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ });
+ }
+
+ protected Animator getCloseAnimation() {
+ AnimatorSet closeAnimation = new AnimatorSet();
+
+ Animator outlineAnimation = mOutlineAnimationProgress.animateToValue(0f);
+ outlineAnimation.setDuration(OUTLINE_ANIMATION_DURATION_MS);
+ outlineAnimation.setInterpolator(CLOSE_OUTLINE_INTERPOLATOR);
+ closeAnimation.play(outlineAnimation);
+
+ Animator alphaAnimation = ObjectAnimator.ofFloat(this, ALPHA, 1f, 0f);
+ alphaAnimation.setStartDelay(ALPHA_ANIMATION_START_DELAY_MS);
+ alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION_MS);
+ closeAnimation.play(alphaAnimation);
+
+ Animator translationYAnimation = ObjectAnimator.ofFloat(
+ mScrollView, TRANSLATION_Y, 0, -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP));
+ translationYAnimation.setDuration(CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS);
+ translationYAnimation.setInterpolator(CLOSE_TRANSLATION_Y_INTERPOLATOR);
+ closeAnimation.play(translationYAnimation);
+
+ Animator contentAlphaAnimation = ObjectAnimator.ofFloat(mScrollView, ALPHA, 1f, 0f);
+ contentAlphaAnimation.setDuration(CONTENT_ALPHA_ANIMATION_DURATION_MS);
+ closeAnimation.play(contentAlphaAnimation);
+
+ closeAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ if (mOpenAnimation != null) {
+ mOpenAnimation.cancel();
+ }
+ }
+ });
+
+ return closeAnimation;
+ }
+
+ private void animateOpen(int currentFocusIndexOverride) {
+ if (mOpenAnimation != null) {
+ // Restart animation since currentFocusIndexOverride can change the initial scroll.
+ mOpenAnimation.cancel();
+ }
+ mOpenAnimation = new AnimatorSet();
+
+ Animator outlineAnimation = mOutlineAnimationProgress.animateToValue(1f);
+ outlineAnimation.setDuration(OUTLINE_ANIMATION_DURATION_MS);
+ mOpenAnimation.play(outlineAnimation);
+
+ Animator alphaAnimation = ObjectAnimator.ofFloat(this, ALPHA, 0f, 1f);
+ alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION_MS);
+ mOpenAnimation.play(alphaAnimation);
+
+ Animator translationXAnimation = ObjectAnimator.ofFloat(
+ mScrollView, TRANSLATION_X, -Utilities.dpToPx(CONTENT_START_TRANSLATION_X_DP), 0);
+ translationXAnimation.setDuration(CONTENT_TRANSLATION_X_ANIMATION_DURATION_MS);
+ translationXAnimation.setInterpolator(OPEN_TRANSLATION_X_INTERPOLATOR);
+ mOpenAnimation.play(translationXAnimation);
+
+ Animator translationYAnimation = ObjectAnimator.ofFloat(
+ mScrollView, TRANSLATION_Y, -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP), 0);
+ translationYAnimation.setDuration(CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS);
+ translationYAnimation.setInterpolator(OPEN_TRANSLATION_Y_INTERPOLATOR);
+ mOpenAnimation.play(translationYAnimation);
+
+ Animator contentAlphaAnimation = ObjectAnimator.ofFloat(mScrollView, ALPHA, 0f, 1f);
+ contentAlphaAnimation.setStartDelay(CONTENT_ALPHA_ANIMATION_START_DELAY_MS);
+ contentAlphaAnimation.setDuration(CONTENT_ALPHA_ANIMATION_DURATION_MS);
+ mOpenAnimation.play(contentAlphaAnimation);
+
+ ViewOutlineProvider outlineProvider = getOutlineProvider();
+ mOpenAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ setClipToPadding(false);
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(
+ /* rect= */ new Rect(
+ /* left= */ 0,
+ /* top= */ 0,
+ /* right= */ getWidth(),
+ /* bottom= */
+ (int) (getHeight() * Utilities.mapBoundToRange(
+ mOutlineAnimationProgress.value,
+ /* lowerBound= */ 0f,
+ /* upperBound= */ 1f,
+ /* toMin= */ OUTLINE_START_HEIGHT_FACTOR,
+ /* toMax= */ 1f,
+ OPEN_OUTLINE_INTERPOLATOR))),
+ /* radius= */ mOutlineRadius * Utilities.mapBoundToRange(
+ mOutlineAnimationProgress.value,
+ /* lowerBound= */ 0f,
+ /* upperBound= */ 1f,
+ /* toMin= */ OUTLINE_START_RADIUS_FACTOR,
+ /* toMax= */ 1f,
+ OPEN_OUTLINE_INTERPOLATOR));
+ }
+ });
+ if (currentFocusIndexOverride == -1) {
+ initializeScroll(/* index= */ 0, /* shouldTruncateTarget= */ false);
+ } else {
+ animateFocusMove(-1, currentFocusIndexOverride);
+ }
+ mScrollView.setVisibility(VISIBLE);
+ setVisibility(VISIBLE);
+ requestFocus();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ setClipToPadding(true);
+ setOutlineProvider(outlineProvider);
+ invalidateOutline();
+ mOpenAnimation = null;
+ }
+ });
+
+ mOpenAnimation.start();
+ }
+
+ protected void animateFocusMove(int fromIndex, int toIndex) {
+ KeyboardQuickSwitchTaskView focusedTask = getTaskAt(toIndex);
+ if (focusedTask == null) {
+ return;
+ }
+ AnimatorSet focusAnimation = new AnimatorSet();
+ focusAnimation.play(focusedTask.getFocusAnimator(true));
+
+ KeyboardQuickSwitchTaskView previouslyFocusedTask = getTaskAt(fromIndex);
+ if (previouslyFocusedTask != null) {
+ focusAnimation.play(previouslyFocusedTask.getFocusAnimator(false));
+ }
+
+ focusAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ focusedTask.requestAccessibilityFocus();
+ if (fromIndex == -1) {
+ int firstVisibleTaskIndex = toIndex == 0
+ ? toIndex
+ : getTaskAt(toIndex - 1) == null
+ ? toIndex : toIndex - 1;
+ // Scroll so that the previous task view is truncated as a visual hint that
+ // there are more tasks
+ initializeScroll(
+ firstVisibleTaskIndex,
+ /* shouldTruncateTarget= */ firstVisibleTaskIndex != toIndex);
+ } else if (toIndex > fromIndex || toIndex == 0) {
+ // Scrolling to next task view
+ if (mIsRtl) {
+ scrollRightTo(focusedTask);
+ } else {
+ scrollLeftTo(focusedTask);
+ }
+ } else {
+ // Scrolling to previous task view
+ if (mIsRtl) {
+ scrollLeftTo(focusedTask);
+ } else {
+ scrollRightTo(focusedTask);
+ }
+ }
+ if (mViewCallbacks != null) {
+ mViewCallbacks.updateCurrentFocusIndex(toIndex);
+ }
+ }
+ });
+
+ focusAnimation.start();
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return (mViewCallbacks != null && mViewCallbacks.onKeyUp(keyCode, event, mIsRtl))
+ || super.onKeyUp(keyCode, event);
+ }
+
+ private void initializeScroll(int index, boolean shouldTruncateTarget) {
+ View task = getTaskAt(index);
+ if (task == null) {
+ return;
+ }
+ if (mIsRtl) {
+ scrollRightTo(
+ task, shouldTruncateTarget, /* smoothScroll= */ false);
+ } else {
+ scrollLeftTo(
+ task, shouldTruncateTarget, /* smoothScroll= */ false);
+ }
+ }
+
+ private void scrollRightTo(@NonNull View targetTask) {
+ scrollRightTo(targetTask, /* shouldTruncateTarget= */ false, /* smoothScroll= */ true);
+ }
+
+ private void scrollRightTo(
+ @NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) {
+ if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) {
+ return;
+ }
+ int scrollTo = targetTask.getLeft() - mSpacing
+ + (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0);
+ // Scroll so that the focused task is to the left of the list
+ if (smoothScroll) {
+ mScrollView.smoothScrollTo(scrollTo, 0);
+ } else {
+ mScrollView.scrollTo(scrollTo, 0);
+ }
+ }
+
+ private void scrollLeftTo(@NonNull View targetTask) {
+ scrollLeftTo(targetTask, /* shouldTruncateTarget= */ false, /* smoothScroll= */ true);
+ }
+
+ private void scrollLeftTo(
+ @NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) {
+ if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) {
+ return;
+ }
+ int scrollTo = targetTask.getRight() + mSpacing - mScrollView.getWidth()
+ - (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0);
+ // Scroll so that the focused task is to the right of the list
+ if (smoothScroll) {
+ mScrollView.smoothScrollTo(scrollTo, 0);
+ } else {
+ mScrollView.scrollTo(scrollTo, 0);
+ }
+ }
+
+ private boolean shouldScroll(@NonNull View targetTask, boolean shouldTruncateTarget) {
+ boolean isTargetTruncated =
+ targetTask.getRight() + mSpacing > mScrollView.getScrollX() + mScrollView.getWidth()
+ || Math.max(0, targetTask.getLeft() - mSpacing) < mScrollView.getScrollX();
+
+ return isTargetTruncated && !shouldTruncateTarget;
+ }
+
+ @Nullable
+ protected KeyboardQuickSwitchTaskView getTaskAt(int index) {
+ return index < 0 || index >= mContent.getChildCount()
+ ? null : (KeyboardQuickSwitchTaskView) mContent.getChildAt(index);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
new file mode 100644
index 0000000..c1f764f
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.animation.Animator;
+import android.view.KeyEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
+import com.android.quickstep.util.GroupTask;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Handles initialization of the {@link KeyboardQuickSwitchView} and supplies it with the list of
+ * tasks.
+ */
+public class KeyboardQuickSwitchViewController {
+
+ @NonNull private final ViewCallbacks mViewCallbacks = new ViewCallbacks();
+ @NonNull private final TaskbarControllers mControllers;
+ @NonNull private final TaskbarOverlayContext mOverlayContext;
+ @NonNull private final KeyboardQuickSwitchView mKeyboardQuickSwitchView;
+ @NonNull private final KeyboardQuickSwitchController.ControllerCallbacks mControllerCallbacks;
+
+ @Nullable private Animator mCloseAnimation;
+
+ private int mCurrentFocusIndex = -1;
+
+ protected KeyboardQuickSwitchViewController(
+ @NonNull TaskbarControllers controllers,
+ @NonNull TaskbarOverlayContext overlayContext,
+ @NonNull KeyboardQuickSwitchView keyboardQuickSwitchView,
+ @NonNull KeyboardQuickSwitchController.ControllerCallbacks controllerCallbacks) {
+ mControllers = controllers;
+ mOverlayContext = overlayContext;
+ mKeyboardQuickSwitchView = keyboardQuickSwitchView;
+ mControllerCallbacks = controllerCallbacks;
+ }
+
+ protected int getCurrentFocusedIndex() {
+ return mCurrentFocusIndex;
+ }
+
+ protected void openQuickSwitchView(
+ @NonNull List<GroupTask> tasks,
+ int numHiddenTasks,
+ boolean updateTasks,
+ int currentFocusIndexOverride) {
+ TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer();
+ dragLayer.addView(mKeyboardQuickSwitchView);
+ dragLayer.runOnClickOnce(v -> closeQuickSwitchView(true));
+
+ mKeyboardQuickSwitchView.applyLoadPlan(
+ mOverlayContext,
+ tasks,
+ numHiddenTasks,
+ updateTasks,
+ currentFocusIndexOverride,
+ mViewCallbacks);
+ }
+
+ protected void closeQuickSwitchView(boolean animate) {
+ if (mCloseAnimation != null) {
+ if (animate) {
+ // Let currently-running animation finish.
+ return;
+ } else {
+ mCloseAnimation.cancel();
+ }
+ }
+ if (!animate) {
+ mCloseAnimation = null;
+ onCloseComplete();
+ return;
+ }
+ mCloseAnimation = mKeyboardQuickSwitchView.getCloseAnimation();
+
+ mCloseAnimation.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mCloseAnimation = null;
+ onCloseComplete();
+ }
+ });
+ mCloseAnimation.start();
+ }
+
+ /**
+ * Launched the currently-focused task.
+ *
+ * Returns index -1 iff the RecentsView shouldn't be opened.
+ *
+ * If the index is not -1, then the {@link com.android.quickstep.views.TaskView} at the returned
+ * index will be focused.
+ */
+ protected int launchFocusedTask() {
+ // Launch the second-most recent task if the user quick switches too quickly, if possible.
+ return launchTaskAt(mCurrentFocusIndex == -1
+ ? (mControllerCallbacks.getTaskCount() > 1 ? 1 : 0) : mCurrentFocusIndex);
+ }
+
+ private int launchTaskAt(int index) {
+ if (mCloseAnimation != null) {
+ // Ignore taps on task views and alt key unpresses while the close animation is running.
+ return -1;
+ }
+ // Even with a valid index, this can be null if the user tries to quick switch before the
+ // views have been added in the KeyboardQuickSwitchView.
+ View taskView = mKeyboardQuickSwitchView.getTaskAt(index);
+ GroupTask task = mControllerCallbacks.getTaskAt(index);
+ if (task == null) {
+ return Math.max(0, index);
+ } else if (task.task2 == null) {
+ UI_HELPER_EXECUTOR.execute(() ->
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(
+ task.task1.key,
+ mControllers.taskbarActivityContext.getActivityLaunchOptions(
+ taskView == null ? mKeyboardQuickSwitchView : taskView, null)
+ .options));
+ } else {
+ mControllers.uiController.launchSplitTasks(
+ taskView == null ? mKeyboardQuickSwitchView : taskView, task);
+ }
+ return -1;
+ }
+
+ private void onCloseComplete() {
+ mOverlayContext.getDragLayer().removeView(mKeyboardQuickSwitchView);
+ mControllerCallbacks.onCloseComplete();
+ }
+
+ protected void onDestroy() {
+ closeQuickSwitchView(false);
+ }
+
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "KeyboardQuickSwitchViewController:");
+
+ pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
+ pw.println(prefix + "\tcloseAnimationRunning=" + (mCloseAnimation != null));
+ pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
+ }
+
+ class ViewCallbacks {
+
+ boolean onKeyUp(int keyCode, KeyEvent event, boolean isRTL) {
+ if (keyCode != KeyEvent.KEYCODE_TAB
+ && keyCode != KeyEvent.KEYCODE_DPAD_RIGHT
+ && keyCode != KeyEvent.KEYCODE_DPAD_LEFT
+ && keyCode != KeyEvent.KEYCODE_GRAVE
+ && keyCode != KeyEvent.KEYCODE_ESCAPE) {
+ return false;
+ }
+ if (keyCode == KeyEvent.KEYCODE_GRAVE || keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ closeQuickSwitchView(true);
+ return true;
+ }
+ boolean traverseBackwards = (keyCode == KeyEvent.KEYCODE_TAB && event.isShiftPressed())
+ || (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && !isRTL)
+ || (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && isRTL);
+ int taskCount = mControllerCallbacks.getTaskCount();
+ int toIndex = mCurrentFocusIndex == -1
+ // Focus the second-most recent app if possible
+ ? (taskCount > 1 ? 1 : 0)
+ : (traverseBackwards
+ // focus a more recent task or loop back to the opposite end
+ ? Math.max(0, mCurrentFocusIndex == 0
+ ? taskCount - 1 : mCurrentFocusIndex - 1)
+ // focus a less recent app or loop back to the opposite end
+ : ((mCurrentFocusIndex + 1) % taskCount));
+
+ mKeyboardQuickSwitchView.animateFocusMove(mCurrentFocusIndex, toIndex);
+
+ return true;
+ }
+
+ void updateCurrentFocusIndex(int index) {
+ mCurrentFocusIndex = index;
+ }
+
+ void launchTappedTask(int index) {
+ KeyboardQuickSwitchViewController.this.launchTaskAt(index);
+ closeQuickSwitchView(true);
+ }
+
+ void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback) {
+ mControllerCallbacks.updateThumbnailInBackground(task, callback);
+ }
+
+ void updateTitleInBackground(Task task, Consumer<Task> callback) {
+ mControllerCallbacks.updateTitleInBackground(task, callback);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 335482c..b00c4cb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.TaskTransitionSpec;
+import android.view.View;
import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
@@ -40,7 +41,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
@@ -49,6 +49,7 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.RecentsView;
import java.io.PrintWriter;
@@ -84,7 +85,6 @@
};
// Initialized in init.
- private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
private TaskbarKeyguardController mKeyguardController;
private final TaskbarLauncherStateController
mTaskbarLauncherStateController = new TaskbarLauncherStateController();
@@ -98,8 +98,6 @@
super.init(taskbarControllers);
mTaskbarLauncherStateController.init(mControllers, mLauncher);
- mTaskbarOverrideBackgroundAlpha = mControllers.taskbarDragLayerController
- .getOverrideBackgroundAlpha();
mLauncher.setTaskbarUIController(this);
mKeyguardController = taskbarControllers.taskbarKeyguardController;
@@ -254,13 +252,6 @@
}
/**
- * Sets whether the background behind the taskbar/nav bar should be hidden.
- */
- public void forceHideBackground(boolean forceHide) {
- mTaskbarOverrideBackgroundAlpha.updateValue(forceHide ? 0 : 1);
- }
-
- /**
* Starts a Taskbar EDU flow, if the user should see one upon launching an application.
*/
public void showEduOnAppLaunch() {
@@ -310,26 +301,12 @@
@Override
public void onTaskbarIconLaunched(ItemInfo item) {
+ super.onTaskbarIconLaunched(item);
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
instanceId);
}
- @Override
- public void setSystemGestureInProgress(boolean inProgress) {
- super.setSystemGestureInProgress(inProgress);
- if (DisplayController.isTransientTaskbar(mLauncher)) {
- forceHideBackground(false);
- return;
- }
- if (!FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
- // Launcher's ScrimView will draw the background throughout the gesture. But once the
- // gesture ends, start drawing taskbar's background again since launcher might stop
- // drawing.
- forceHideBackground(inProgress);
- }
- }
-
/**
* Animates Taskbar elements during a transition to a Launcher state that should use in-app
* layouts.
@@ -380,13 +357,24 @@
}
@Override
+ public RecentsView getRecentsView() {
+ return mLauncher.getOverviewPanel();
+ }
+
+ @Override
+ public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
+ mLauncher.launchSplitTasks(taskView, groupTask);
+ }
+
+ @Override
+ protected void onIconLayoutBoundsChanged() {
+ mTaskbarLauncherStateController.resetIconAlignment();
+ }
+
+ @Override
public void dumpLogs(String prefix, PrintWriter pw) {
super.dumpLogs(prefix, pw);
- pw.println(String.format(
- "%s\tmTaskbarOverrideBackgroundAlpha=%.2f",
- prefix,
- mTaskbarOverrideBackgroundAlpha.value));
pw.println(String.format("%s\tTaskbar in-app display progress:", prefix));
mTaskbarInAppDisplayProgressMultiProp.dump(
prefix + "\t",
@@ -399,9 +387,4 @@
mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
}
-
- @Override
- public RecentsView getRecentsView() {
- return mLauncher.getOverviewPanel();
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 74e7375..f082fc6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -78,6 +80,10 @@
private float mStartProgressForNextRevealAnim;
private boolean mWasLastRevealAnimReversed;
+ // States that affect whether region sampling is enabled or not
+ private boolean mIsStashed;
+ private boolean mTaskbarHidden;
+
public StashedHandleViewController(TaskbarActivityContext activity,
StashedHandleView stashedHandleView) {
mActivity = activity;
@@ -145,6 +151,14 @@
}
}
+ /**
+ * Returns the stashed handle bounds.
+ * @param out The destination rect.
+ */
+ public void getStashedHandleBounds(Rect out) {
+ out.set(mStashedHandleBounds);
+ }
+
private void initRegionSampler() {
mRegionSamplingHelper = new RegionSamplingHelper(mStashedHandleView,
new RegionSamplingHelper.SamplingCallback() {
@@ -187,16 +201,19 @@
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
+ float startRadius = mStashedHandleRadius;
if (DisplayController.isTransientTaskbar(mActivity)) {
// Account for the full visual height of the transient taskbar.
int heightDiff = (mTaskbarSize - visualBounds.height()) / 2;
visualBounds.top -= heightDiff;
visualBounds.bottom += heightDiff;
+
+ startRadius = visualBounds.height() / 2f;
}
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
- mStashedHandleRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds);
+ startRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds);
boolean isReversed = !isStashed;
boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
@@ -218,7 +235,8 @@
/** Called when taskbar is stashed or unstashed. */
public void onIsStashedChanged(boolean isStashed) {
- mRegionSamplingHelper.setWindowVisible(isStashed);
+ mIsStashed = isStashed;
+ updateRegionSamplingWindowVisibility();
if (isStashed) {
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
mRegionSamplingHelper.start(mStashedHandleView.getSampledRegion());
@@ -247,6 +265,15 @@
homeDisabled ? 0 : 1);
}
+ public void updateStateForSysuiFlags(int systemUiStateFlags) {
+ mTaskbarHidden = (systemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
+ updateRegionSamplingWindowVisibility();
+ }
+
+ private void updateRegionSamplingWindowVisibility() {
+ mRegionSamplingHelper.setWindowVisible(mIsStashed && !mTaskbarHidden);
+ }
+
public boolean isStashedHandleVisible() {
return mStashedHandleView.getVisibility() == View.VISIBLE;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index c6d8fce..5c4f3e1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -46,6 +45,7 @@
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace;
@@ -89,6 +89,7 @@
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.PackageManagerHelper;
@@ -106,7 +107,6 @@
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
-import java.util.function.Consumer;
/**
* The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
@@ -219,8 +219,8 @@
new TaskbarScrimViewController(this, taskbarScrimView),
new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider,
mWindowManager,
- new RotationChangeProvider(WindowManagerGlobal.getWindowManagerService(), this,
- getMainExecutor())),
+ new RotationChangeProvider(c.getSystemService(DisplayManager.class), this,
+ getMainThreadHandler())),
new TaskbarKeyguardController(this),
new StashedHandleViewController(this, stashedHandleView),
new TaskbarStashController(this),
@@ -236,7 +236,8 @@
isDesktopMode
? new DesktopTaskbarRecentAppsController(this)
: TaskbarRecentAppsController.DEFAULT,
- new TaskbarEduTooltipController(this));
+ new TaskbarEduTooltipController(this),
+ new KeyboardQuickSwitchController());
}
public void init(@NonNull TaskbarSharedState sharedState) {
@@ -247,6 +248,12 @@
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
+ disableNavBarElements(sharedState.disableNavBarDisplayId, sharedState.disableNavBarState1,
+ sharedState.disableNavBarState2, false /* animate */);
+ onSystemBarAttributesChanged(sharedState.systemBarAttrsDisplayId,
+ sharedState.systemBarAttrsBehavior);
+ onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
+
if (!mAddedWindow) {
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
@@ -554,8 +561,6 @@
public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
- mControllers.taskbarViewController.setImeIsVisible(
- mControllers.navbarButtonsViewController.isImeVisible());
int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
onNotificationShadeExpandChanged((systemUiStateFlags & shadeExpandedFlags) != 0, fromInit);
@@ -564,6 +569,7 @@
|| isNavBarKidsModeActive());
mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
mControllers.navbarButtonsViewController.isHomeDisabled());
+ mControllers.stashedHandleViewController.updateStateForSysuiFlags(systemUiStateFlags);
mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
mControllers.taskbarStashController.updateStateForSysuiFlags(
systemUiStateFlags, fromInit || !isUserSetupComplete());
@@ -829,15 +835,17 @@
launchFromTaskbarPreservingSplitIfVisible(recents, info);
}
- mControllers.uiController.onTaskbarIconLaunched(info);
} catch (NullPointerException
| ActivityNotFoundException
| SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
.show();
Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
+ return;
}
+
}
+ mControllers.uiController.onTaskbarIconLaunched(info);
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
}
} else if (tag instanceof AppInfo) {
@@ -851,8 +859,8 @@
taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
} else {
launchFromTaskbarPreservingSplitIfVisible(recents, info);
- mControllers.uiController.onTaskbarIconLaunched(info);
}
+ mControllers.uiController.onTaskbarIconLaunched(info);
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} else if (tag instanceof ItemClickProxy) {
((ItemClickProxy) tag).onItemClicked(view);
@@ -870,9 +878,10 @@
* (potentially breaking a split pair).
*/
private void launchFromTaskbarPreservingSplitIfVisible(RecentsView recents, ItemInfo info) {
- recents.findLastActiveTaskAndRunCallback(
- info.getTargetComponent(),
- (Consumer<Task>) foundTask -> {
+ ComponentKey componentToBeLaunched = new ComponentKey(info.getTargetComponent(), info.user);
+ recents.getSplitSelectController().findLastActiveTaskAndRunCallback(
+ componentToBeLaunched,
+ foundTask -> {
if (foundTask != null) {
TaskView foundTaskView =
recents.getTaskViewByTaskId(foundTask.key.id);
@@ -1061,6 +1070,12 @@
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
+ void notifyUpdateLayoutParams() {
+ if (mDragLayer.isAttachedToWindow()) {
+ mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
+ }
+ }
+
public void showPopupMenuForIcon(BubbleTextView btv) {
setTaskbarWindowFullscreen(true);
btv.post(() -> mControllers.taskbarPopupController.showForIcon(btv));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index 2bfc7dd..1a54576 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -41,12 +41,15 @@
public static final int FLAG_AUTOHIDE_SUSPEND_TOUCHING = 1 << 2;
// Taskbar EDU overlay is open above the Taskbar. */
public static final int FLAG_AUTOHIDE_SUSPEND_EDU_OPEN = 1 << 3;
+ // Taskbar in immersive mode in overview
+ public static final int FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER = 1 << 4;
@IntDef(flag = true, value = {
FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
FLAG_AUTOHIDE_SUSPEND_DRAGGING,
FLAG_AUTOHIDE_SUSPEND_TOUCHING,
FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
+ FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AutohideSuspendFlag {}
@@ -92,6 +95,10 @@
return mAutohideSuspendFlags != 0;
}
+ public boolean isSuspendedForTransientTaskbarInOverview() {
+ return (mAutohideSuspendFlags & FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER) != 0;
+ }
+
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarAutohideSuspendController:");
@@ -106,6 +113,8 @@
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_DRAGGING, "FLAG_AUTOHIDE_SUSPEND_DRAGGING");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TOUCHING, "FLAG_AUTOHIDE_SUSPEND_TOUCHING");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_EDU_OPEN, "FLAG_AUTOHIDE_SUSPEND_EDU_OPEN");
+ appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
+ "FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER");
return str.toString();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 82f27ae..e00bc59 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -20,7 +20,9 @@
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
+import android.graphics.RectF
import com.android.launcher3.R
+import com.android.launcher3.Utilities.mapRange
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.anim.Interpolators
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
@@ -29,7 +31,8 @@
/** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
- val paint: Paint = Paint()
+ val paint = Paint()
+ val lastDrawnTransientRect = RectF()
var backgroundHeight = context.deviceProfile.taskbarSize.toFloat()
var translationYForSwipe = 0f
@@ -51,6 +54,12 @@
private val invertedLeftCornerPath: Path = Path()
private val invertedRightCornerPath: Path = Path()
+ private val stashedHandleWidth =
+ context.resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width)
+
+ private val stashedHandleHeight =
+ context.resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_height)
+
init {
paint.color = context.getColor(R.color.taskbar_background)
paint.flags = Paint.ANTI_ALIAS_FLAG
@@ -70,6 +79,7 @@
/**
* Sets the roundness of the round corner above Taskbar. No effect on transient Taskkbar.
+ *
* @param cornerRoundness 0 has no round corner, 1 has complete round corner.
*/
fun setCornerRoundness(cornerRoundness: Float) {
@@ -98,8 +108,8 @@
/** Draws the background with the given paint and height, on the provided canvas. */
fun draw(canvas: Canvas) {
canvas.save()
- canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
if (!isTransientTaskbar || transientBackgroundBounds.isEmpty) {
+ canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
// Draw the background behind taskbar content.
canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint)
@@ -110,13 +120,25 @@
canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
canvas.drawPath(invertedRightCornerPath, paint)
} else {
- // Approximates the stash/unstash animation to transform the background.
- val scaleFactor = backgroundHeight / maxBackgroundHeight
- val width = transientBackgroundBounds.width()
- val widthScale = mapToRange(scaleFactor, 0f, 1f, 0.2f, 1f, Interpolators.LINEAR)
- val newWidth = widthScale * width
- val delta = width - newWidth
- canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f))
+ // backgroundHeight is a value from [0...maxBackgroundHeight], so we can use it as a
+ // proxy to figure out the animation progress of the stash/unstash animation.
+ val progress = backgroundHeight / maxBackgroundHeight
+
+ // At progress 0, we draw the background as the stashed handle.
+ // At progress 1, we draw the background as the full taskbar.
+ val newBackgroundHeight =
+ mapRange(progress, stashedHandleHeight.toFloat(), maxBackgroundHeight)
+ val fullWidth = transientBackgroundBounds.width()
+ val newWidth = mapRange(progress, stashedHandleWidth.toFloat(), fullWidth.toFloat())
+ val halfWidthDelta = (fullWidth - newWidth) / 2f
+ val radius = newBackgroundHeight / 2f
+ val bottomMarginProgress = bottomMargin * ((1f - progress) / 2f)
+
+ // Aligns the bottom with the bottom of the stashed handle.
+ val bottom =
+ canvas.height - bottomMargin +
+ bottomMarginProgress +
+ (-mapRange(1f - progress, 0f, stashedHandleHeight / 2f) + translationYForSwipe)
// Draw shadow.
val shadowAlpha =
@@ -128,20 +150,15 @@
setColorAlphaBound(Color.BLACK, Math.round(shadowAlpha))
)
- // Draw background.
- val radius = backgroundHeight / 2f
-
- canvas.drawRoundRect(
- transientBackgroundBounds.left + (delta / 2f),
- translationYForSwipe,
- transientBackgroundBounds.right - (delta / 2f),
- backgroundHeight + translationYForSwipe,
- radius,
- radius,
- paint
+ lastDrawnTransientRect.set(
+ transientBackgroundBounds.left + halfWidthDelta,
+ bottom - newBackgroundHeight,
+ transientBackgroundBounds.right - halfWidthDelta,
+ bottom
)
- }
+ canvas.drawRoundRect(lastDrawnTransientRect, radius, radius, paint)
+ }
canvas.restore()
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index ea70de4..931d79f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -59,6 +59,7 @@
public final TaskbarTranslationController taskbarTranslationController;
public final TaskbarOverlayController taskbarOverlayController;
public final TaskbarEduTooltipController taskbarEduTooltipController;
+ public final KeyboardQuickSwitchController keyboardQuickSwitchController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null;
@@ -103,7 +104,8 @@
VoiceInteractionWindowController voiceInteractionWindowController,
TaskbarTranslationController taskbarTranslationController,
TaskbarRecentAppsController taskbarRecentAppsController,
- TaskbarEduTooltipController taskbarEduTooltipController) {
+ TaskbarEduTooltipController taskbarEduTooltipController,
+ KeyboardQuickSwitchController keyboardQuickSwitchController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -127,6 +129,7 @@
this.taskbarTranslationController = taskbarTranslationController;
this.taskbarRecentAppsController = taskbarRecentAppsController;
this.taskbarEduTooltipController = taskbarEduTooltipController;
+ this.keyboardQuickSwitchController = keyboardQuickSwitchController;
}
/**
@@ -159,6 +162,7 @@
taskbarRecentAppsController.init(this);
taskbarTranslationController.init(this);
taskbarEduTooltipController.init(this);
+ keyboardQuickSwitchController.init(this);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -167,7 +171,7 @@
stashedHandleViewController, taskbarStashController, taskbarEduController,
taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
voiceInteractionWindowController, taskbarTranslationController,
- taskbarEduTooltipController
+ taskbarEduTooltipController, keyboardQuickSwitchController
};
mBackgroundRendererControllers = new BackgroundRendererController[] {
taskbarDragLayerController, taskbarScrimViewController,
@@ -191,6 +195,7 @@
public void onConfigurationChanged(@Config int configChanges) {
navbarButtonsViewController.onConfigurationChanged(configChanges);
taskbarDragLayerController.onConfigurationChanged();
+ keyboardQuickSwitchController.onConfigurationChanged(configChanges);
}
/**
@@ -216,6 +221,7 @@
taskbarInsetsController.onDestroy();
voiceInteractionWindowController.onDestroy();
taskbarRecentAppsController.onDestroy();
+ keyboardQuickSwitchController.onDestroy();
mControllersToLog = null;
mBackgroundRendererControllers = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index d1fea7b..4e79011 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -33,6 +33,7 @@
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.Pair;
@@ -69,11 +70,13 @@
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.quickstep.util.LogUtils;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.systemui.shared.recents.model.Task;
+import com.android.wm.shell.draganddrop.DragAndDropConstants;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -310,9 +313,6 @@
if (mDisallowGlobalDrag) {
AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS);
} else {
- // stash the transient taskbar
- mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
-
AbstractFloatingView.closeAllOpenViews(mActivity);
}
@@ -340,7 +340,7 @@
if (DEBUG_DRAG_SHADOW_SURFACE) {
canvas.drawColor(0xffff0000);
}
- float scale = mDragObject.dragView.getScaleX();
+ float scale = mDragObject.dragView.getEndScale();
canvas.scale(scale, scale);
mDragObject.dragView.draw(canvas);
canvas.restore();
@@ -395,6 +395,15 @@
com.android.launcher3.logging.InstanceId launcherInstanceId = instanceIds.second;
intent.putExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, internalInstanceId);
+ if (DisplayController.isTransientTaskbar(mActivity)) {
+ // Tell WM Shell to ignore drag events in the provided transient taskbar region.
+ TaskbarDragLayer dragLayer = mControllers.taskbarActivityContext.getDragLayer();
+ int[] locationOnScreen = dragLayer.getLocationOnScreen();
+ RectF disallowExternalDropRegion = new RectF(dragLayer.getLastDrawnTransientRect());
+ disallowExternalDropRegion.offset(locationOnScreen[0], locationOnScreen[1]);
+ intent.putExtra(DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION,
+ disallowExternalDropRegion);
+ }
ClipData clipData = new ClipData(clipDescription, new ClipData.Item(intent));
if (btv.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
@@ -421,9 +430,6 @@
if (dragEvent.getResult()) {
maybeOnDragEnd();
} else {
- // un-stash the transient taskbar in case drag and drop was canceled
- mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
-
// This will take care of calling maybeOnDragEnd() after the animation
animateGlobalDragViewToOriginalPosition(btv, dragEvent);
}
@@ -451,6 +457,9 @@
mControllers.taskbarAutohideSuspendController.updateFlag(
TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false);
mActivity.onDragEnd();
+ // Note, this must be done last to ensure no AutohideSuspendFlags are active, as that
+ // will prevent us from stashing until the timeout.
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
}
}
@@ -592,7 +601,15 @@
View target = findTaskbarTargetForIconView(originalView);
int[] toPosition = target.getLocationOnScreen();
- float toScale = (float) target.getWidth() / mDragIconSize;
+ float iconSize = target.getWidth();
+ if (target instanceof BubbleTextView) {
+ Rect bounds = new Rect();
+ ((BubbleTextView) target).getSourceVisualDragBounds(bounds);
+ toPosition[0] += bounds.left;
+ toPosition[1] += bounds.top;
+ iconSize = bounds.width();
+ }
+ float toScale = iconSize / mDragIconSize;
float toAlpha = (target == originalView) ? 1f : 0f;
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
final FloatProp mDx = new FloatProp(fromX, toPosition[0], 0,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 7114849..58d6244 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -183,6 +184,11 @@
invalidate();
}
+ /** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */
+ protected RectF getLastDrawnTransientRect() {
+ return mBackgroundRenderer.getLastDrawnTransientRect();
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 267bee1..7c4071f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -127,10 +127,6 @@
return mAssistantBgTaskbar;
}
- public AnimatedFloat getOverrideBackgroundAlpha() {
- return mBgOverride;
- }
-
public AnimatedFloat getTaskbarBackgroundOffset() {
return mBgOffset;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 9f24565..f32e025 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -18,16 +18,21 @@
import android.graphics.Insets
import android.graphics.Region
import android.view.InsetsFrameProvider
+import android.view.InsetsFrameProvider.SOURCE_DISPLAY
+import android.view.InsetsFrameProvider.SOURCE_FRAME
import android.view.InsetsState
import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES
import android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT
import android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
+import android.view.InsetsState.ITYPE_LEFT_GESTURES
+import android.view.InsetsState.ITYPE_RIGHT_GESTURES
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD
import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION
+import com.android.internal.policy.GestureNavigationSettingsObserver
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
import com.android.launcher3.DeviceProfile
@@ -45,6 +50,12 @@
private val deviceProfileChangeListener = { _: DeviceProfile ->
onTaskbarWindowHeightOrInsetsChanged()
}
+ private val gestureNavSettingsObserver =
+ GestureNavigationSettingsObserver(
+ context.mainThreadHandler,
+ context,
+ this::onTaskbarWindowHeightOrInsetsChanged
+ )
// Initialized in init.
private lateinit var controllers: TaskbarControllers
@@ -59,18 +70,23 @@
intArrayOf(
ITYPE_EXTRA_NAVIGATION_BAR,
ITYPE_BOTTOM_TAPPABLE_ELEMENT,
- ITYPE_BOTTOM_MANDATORY_GESTURES
- )
+ ITYPE_BOTTOM_MANDATORY_GESTURES,
+ ITYPE_LEFT_GESTURES,
+ ITYPE_RIGHT_GESTURES,
+ ),
+ intArrayOf(SOURCE_FRAME, SOURCE_FRAME, SOURCE_FRAME, SOURCE_DISPLAY, SOURCE_DISPLAY)
)
onTaskbarWindowHeightOrInsetsChanged()
windowLayoutParams.insetsRoundedCornerFrame = true
context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
+ gestureNavSettingsObserver.registerForCallingUser()
}
fun onDestroy() {
context.removeOnDeviceProfileChangeListener(deviceProfileChangeListener)
+ gestureNavSettingsObserver.unregister()
}
fun onTaskbarWindowHeightOrInsetsChanged() {
@@ -83,6 +99,7 @@
)
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
+ val res = context.resources
for (provider in windowLayoutParams.providedInsets) {
if (
provider.type == ITYPE_EXTRA_NAVIGATION_BAR ||
@@ -91,6 +108,22 @@
provider.insetsSize = getInsetsByNavMode(contentHeight)
} else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
provider.insetsSize = getInsetsByNavMode(tappableHeight)
+ } else if (provider.type == ITYPE_LEFT_GESTURES) {
+ provider.insetsSize =
+ Insets.of(
+ gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res),
+ 0,
+ 0,
+ 0
+ )
+ } else if (provider.type == ITYPE_RIGHT_GESTURES) {
+ provider.insetsSize =
+ Insets.of(
+ 0,
+ 0,
+ gestureNavSettingsObserver.getRightSensitivityForCallingUser(res),
+ 0
+ )
}
}
@@ -116,10 +149,12 @@
provider.insetsSizeOverrides = insetsSizeOverride
}
}
+ context.notifyUpdateLayoutParams()
}
/**
* @return [Insets] where the [bottomInset] is either used as a bottom inset or
+ *
* ```
* right/left inset if using 3 button nav
* ```
@@ -137,18 +172,25 @@
/**
* Sets {@param providesInsetsTypes} as the inset types provided by {@param params}.
+ *
* @param params The window layout params.
* @param providesInsetsTypes The inset types we would like this layout params to provide.
*/
- fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray) {
+ fun setProvidesInsetsTypes(
+ params: WindowManager.LayoutParams,
+ providesInsetsTypes: IntArray,
+ providesInsetsSources: IntArray
+ ) {
params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size)
for (i in providesInsetsTypes.indices) {
- params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i])
+ params.providedInsets[i] =
+ InsetsFrameProvider(providesInsetsTypes[i], providesInsetsSources[i], null, null)
}
}
/**
* Called to update the touchable insets.
+ *
* @see InternalInsetsInfo.setTouchableInsets
*/
fun updateInsetsTouchability(insetsInfo: ViewTreeObserver.InternalInsetsInfo) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 178482e..b586487 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
-import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
import static com.android.systemui.animation.Interpolators.EMPHASIZED;
@@ -39,8 +38,8 @@
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
+import com.android.launcher3.util.window.RefreshRateTracker;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.views.RecentsView;
@@ -119,14 +118,10 @@
mLauncherState = finalState;
updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false);
applyState();
- boolean disallowGlobalDrag = finalState instanceof OverviewState;
boolean disallowLongClick = finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
- mControllers.taskbarDragController.setDisallowGlobalDrag(disallowGlobalDrag);
- mControllers.taskbarDragController.setDisallowLongClick(disallowLongClick);
- mControllers.taskbarAllAppsController.setDisallowGlobalDrag(disallowGlobalDrag);
- mControllers.taskbarAllAppsController.setDisallowLongClick(disallowLongClick);
- mControllers.taskbarPopupController.setAllowInitialSplitSelection(
- disallowGlobalDrag);
+ com.android.launcher3.taskbar.Utilities.setOverviewDragState(
+ mControllers, finalState.disallowTaskbarGlobalDrag(),
+ disallowLongClick, finalState.allowTaskbarInitialSplitSelection());
}
};
@@ -142,8 +137,7 @@
mIconAlphaForHome = mControllers.taskbarViewController
.getTaskbarIconAlpha().get(ALPHA_INDEX_HOME);
- mIconAlignment.finishAnimation();
- onIconAlignmentRatioChanged();
+ resetIconAlignment();
mLauncher.getStateManager().addStateListener(mStateListener);
@@ -237,7 +231,7 @@
}
public void applyState() {
- applyState(TASKBAR_STASH_DURATION);
+ applyState(mControllers.taskbarStashController.getStashDuration());
}
public void applyState(long duration) {
@@ -245,7 +239,7 @@
}
public Animator applyState(boolean start) {
- return applyState(TASKBAR_STASH_DURATION, start);
+ return applyState(mControllers.taskbarStashController.getStashDuration(), start);
}
public Animator applyState(long duration, boolean start) {
@@ -332,8 +326,17 @@
+ mTaskbarBackgroundAlpha.value
+ " -> " + backgroundAlpha + ": " + duration);
}
- animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(backgroundAlpha)
- .setDuration(duration));
+
+ Animator taskbarBackgroundAlpha = mTaskbarBackgroundAlpha
+ .animateToValue(backgroundAlpha)
+ .setDuration(duration);
+ // Add a single frame delay to the taskbar bg to avoid too many moving parts during the
+ // app launch animation.
+ taskbarBackgroundAlpha.setStartDelay(
+ (hasAnyFlag(changedFlags, FLAG_RESUMED) && !goingToLauncher)
+ ? RefreshRateTracker.getSingleFrameMs(mLauncher)
+ : 0);
+ animatorSet.play(taskbarBackgroundAlpha);
}
float cornerRoundness = goingToLauncher ? 0 : 1;
@@ -436,6 +439,14 @@
return (mState & FLAGS_LAUNCHER) != 0;
}
+ /**
+ * Resets and updates the icon alignment.
+ */
+ protected void resetIconAlignment() {
+ mIconAlignment.finishAnimation();
+ onIconAlignmentRatioChanged();
+ }
+
private void onIconAlignmentRatioChanged() {
float currentValue = mIconAlphaForHome.getValue();
boolean taskbarWillBeVisible = mIconAlignment.value < 1;
@@ -457,6 +468,11 @@
}
private void updateIconAlphaForHome(float alpha) {
+ if (mControllers.taskbarActivityContext.isDestroyed()) {
+ Log.e("b/260135164", "updateIconAlphaForHome is called after Taskbar is destroyed",
+ new Exception());
+ return;
+ }
mIconAlphaForHome.setValue(alpha);
boolean hotseatVisible = alpha == 0
|| (!mControllers.uiController.isHotseatIconOnTopWhenAligned()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index a58906f..8c91833 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -130,10 +130,10 @@
? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext)
: null;
int configDiff = mOldConfig.diff(newConfig);
+ int configDiffForRecreate = configDiff;
int configsRequiringRecreate = ActivityInfo.CONFIG_ASSETS_PATHS
| ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_UI_MODE
| ActivityInfo.CONFIG_SCREEN_SIZE;
- boolean requiresRecreate = (configDiff & configsRequiringRecreate) != 0;
if ((configDiff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0
&& mTaskbarActivityContext != null && dp != null
&& !isPhoneMode(dp)) {
@@ -146,12 +146,19 @@
int oldWidth = isOrientationChange ? oldDp.heightPx : oldDp.widthPx;
int oldHeight = isOrientationChange ? oldDp.widthPx : oldDp.heightPx;
if (dp.widthPx == oldWidth && dp.heightPx == oldHeight) {
- configDiff &= ~ActivityInfo.CONFIG_SCREEN_SIZE;
- requiresRecreate = (configDiff & configsRequiringRecreate) != 0;
+ configDiffForRecreate &= ~ActivityInfo.CONFIG_SCREEN_SIZE;
+ }
+ }
+ if ((configDiff & ActivityInfo.CONFIG_UI_MODE) != 0) {
+ // Only recreate for theme changes, not other UI mode changes such as docking.
+ int oldUiNightMode = (mOldConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+ int newUiNightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+ if (oldUiNightMode == newUiNightMode) {
+ configDiffForRecreate &= ~ActivityInfo.CONFIG_UI_MODE;
}
}
- if (requiresRecreate) {
+ if ((configDiffForRecreate & configsRequiringRecreate) != 0) {
recreateTaskbar();
} else {
// Config change might be handled without re-creating the taskbar
@@ -362,18 +369,24 @@
}
public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
+ mSharedState.disableNavBarDisplayId = displayId;
+ mSharedState.disableNavBarState1 = state1;
+ mSharedState.disableNavBarState2 = state2;
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.disableNavBarElements(displayId, state1, state2, animate);
}
}
public void onSystemBarAttributesChanged(int displayId, int behavior) {
+ mSharedState.systemBarAttrsDisplayId = displayId;
+ mSharedState.systemBarAttrsBehavior = behavior;
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.onSystemBarAttributesChanged(displayId, behavior);
}
}
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+ mSharedState.navButtonsDarkIntensity = darkIntensity;
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.onNavButtonsDarkIntensityChanged(darkIntensity);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 5e670d294..e46e11b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -199,13 +199,6 @@
hotseatItemInfos = mControllers.taskbarRecentAppsController
.updateHotseatItemInfos(hotseatItemInfos);
mContainer.updateHotseatItems(hotseatItemInfos);
-
- final boolean finalIsHotseatEmpty = isHotseatEmpty;
- mControllers.runAfterInit(() -> {
- mControllers.taskbarStashController.updateStateForFlag(
- TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, finalIsHotseatEmpty);
- mControllers.taskbarStashController.applyState();
- });
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 30d6eb4..115b99e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import android.content.Intent;
@@ -56,6 +57,7 @@
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -152,9 +154,28 @@
return null;
}
- final PopupContainerWithArrow<BaseTaskbarContext> container =
- (PopupContainerWithArrow<BaseTaskbarContext>) context.getLayoutInflater().inflate(
- R.layout.popup_container, context.getDragLayer(), false);
+ PopupContainerWithArrow<BaseTaskbarContext> container;
+ int deepShortcutCount = mPopupDataProvider.getShortcutCountForItem(item);
+ // TODO(b/198438631): add support for INSTALL shortcut factory
+ List<SystemShortcut> systemShortcuts = getSystemShortcuts()
+ .map(s -> s.getShortcut(context, item, icon))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ if (ENABLE_MATERIAL_U_POPUP.get()) {
+ container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+ R.layout.popup_container_material_u, context.getDragLayer(), false);
+ container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
+ } else {
+ container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+ R.layout.popup_container, context.getDragLayer(), false);
+ container.populateAndShow(
+ icon,
+ deepShortcutCount,
+ mPopupDataProvider.getNotificationKeysForItem(item),
+ systemShortcuts);
+ }
+
container.addOnAttachStateChangeListener(
new PopupLiveUpdateHandler<BaseTaskbarContext>(context, container) {
@Override
@@ -165,15 +186,6 @@
// TODO (b/198438631): configure for taskbar/context
container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
mControllers.taskbarDragController.addDragListener(container);
-
- container.populateAndShow(icon,
- mPopupDataProvider.getShortcutCountForItem(item),
- mPopupDataProvider.getNotificationKeysForItem(item),
- // TODO (b/198438631): add support for INSTALL shortcut factory
- getSystemShortcuts()
- .map(s -> s.getShortcut(context, item, icon))
- .filter(Objects::nonNull)
- .collect(Collectors.toList()));
container.requestFocus();
// Make focusable to receive back events
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 87b3789..026eff7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -20,8 +20,21 @@
*/
public class TaskbarSharedState {
+ // TaskbarManager#onSystemUiFlagsChanged
public int sysuiStateFlags;
+ // TaskbarManager#disableNavBarElements()
+ public int disableNavBarDisplayId;
+ public int disableNavBarState1;
+ public int disableNavBarState2;
+
+ // TaskbarManager#onSystemBarAttributesChanged()
+ public int systemBarAttrsDisplayId;
+ public int systemBarAttrsBehavior;
+
+ // TaskbarManager#onNavButtonsDarkIntensityChanged()
+ public float navButtonsDarkIntensity;
+
public boolean setupUIVisible = false;
public boolean allAppsVisible = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c95535b..115db25 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -17,8 +17,10 @@
import static android.view.HapticFeedbackConstants.LONG_PRESS;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.FORCE_PERSISTENT_TASKBAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
@@ -41,6 +43,7 @@
import android.view.InsetsController;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -72,21 +75,20 @@
public static final int FLAG_IN_APP = 1 << 0;
public static final int FLAG_STASHED_IN_APP_MANUAL = 1 << 1; // long press, persisted
public static final int FLAG_STASHED_IN_SYSUI_STATE = 1 << 2; // app pinning, keyguard, etc.
- public static final int FLAG_STASHED_IN_APP_EMPTY = 1 << 3; // no hotseat icons
- public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 4; // setup wizard and AllSetActivity
- public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible
- public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6;
- public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 7; // All apps is visible.
- public static final int FLAG_IN_SETUP = 1 << 8; // In the Setup Wizard
- public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 9; // phone screen gesture nav, stashed
- public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 10; // Autohide (transient taskbar).
+ public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 3; // setup wizard and AllSetActivity
+ public static final int FLAG_STASHED_IN_APP_IME = 1 << 4; // IME is visible
+ public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 5;
+ public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 6; // All apps is visible.
+ public static final int FLAG_IN_SETUP = 1 << 7; // In the Setup Wizard
+ public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 8; // phone screen gesture nav, stashed
+ public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 9; // Autohide (transient taskbar).
// If any of these flags are enabled, isInApp should return true.
private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
- | FLAG_STASHED_IN_SYSUI_STATE | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP
+ | FLAG_STASHED_IN_SYSUI_STATE | FLAG_STASHED_IN_APP_SETUP
| FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_TASKBAR_ALL_APPS
| FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
@@ -102,11 +104,20 @@
/**
* How long to stash/unstash when manually invoked via long press.
+ *
+ * Use {@link #getStashDuration()} to query duration
*/
- public static final long TASKBAR_STASH_DURATION =
+ private static final long TASKBAR_STASH_DURATION =
InsetsController.ANIMATION_DURATION_RESIZE;
/**
+ * How long to stash/unstash transient taskbar.
+ *
+ * Use {@link #getStashDuration()} to query duration.
+ */
+ private static final long TRANSIENT_TASKBAR_STASH_DURATION = 417;
+
+ /**
* How long to stash/unstash when keyboard is appearing/disappearing.
*/
private static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
@@ -114,7 +125,7 @@
/**
* The scale TaskbarView animates to when being stashed.
*/
- private static final float STASHED_TASKBAR_SCALE = 0.3f;
+ protected static final float STASHED_TASKBAR_SCALE = 0.5f;
/**
* How long the hint animation plays, starting on motion down.
@@ -123,6 +134,21 @@
ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT;
/**
+ * How long to delay the icon/stash handle alpha.
+ */
+ private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
+
+ /**
+ * How long the icon/stash handle alpha animation plays.
+ */
+ private static final long TASKBAR_STASH_ALPHA_DURATION = 50;
+
+ /**
+ * How long to delay the icon/stash handle alpha for the home to app taskbar animation.
+ */
+ private static final long TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY = 66;
+
+ /**
* The scale that TaskbarView animates to when hinting towards the stashed state.
*/
private static final float STASHED_TASKBAR_HINT_SCALE = 0.9f;
@@ -300,7 +326,16 @@
boolean hideTaskbar = isVisible || !mActivity.isUserSetupComplete();
updateStateForFlag(FLAG_IN_SETUP, hideTaskbar);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, hideTaskbar);
- applyState(hideTaskbar ? 0 : TASKBAR_STASH_DURATION);
+ applyState(hideTaskbar ? 0 : getStashDuration());
+ }
+
+ /**
+ * Returns how long the stash/unstash animation should play.
+ */
+ public long getStashDuration() {
+ return DisplayController.isTransientTaskbar(mActivity)
+ ? TRANSIENT_TASKBAR_STASH_DURATION
+ : TASKBAR_STASH_DURATION;
}
/**
@@ -425,7 +460,9 @@
return;
}
- if (stash && mControllers.taskbarAutohideSuspendController.isSuspended()) {
+ if (stash && mControllers.taskbarAutohideSuspendController.isSuspended()
+ && !mControllers.taskbarAutohideSuspendController
+ .isSuspendedForTransientTaskbarInOverview()) {
// Avoid stashing if autohide is currently suspended.
return;
}
@@ -515,7 +552,10 @@
}
mAnimator = new AnimatorSet();
addJankMonitorListener(mAnimator, /* appearing= */ !mIsStashed);
- final float stashTranslation = isPhoneMode() ? 0 : (mUnstashedHeight - mStashedHeight);
+ boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
+ final float stashTranslation = isPhoneMode() || isTransientTaskbar
+ ? 0
+ : (mUnstashedHeight - mStashedHeight);
if (!supportsVisualStashing()) {
// Just hide/show the icons and background instead of stashing into a handle.
@@ -523,8 +563,8 @@
.setDuration(duration));
mAnimator.playTogether(mTaskbarBackgroundOffset.animateToValue(isStashed ? 1 : 0)
.setDuration(duration));
- mAnimator.playTogether(mIconTranslationYForStash.animateToValue(isStashed ?
- stashTranslation : 0)
+ mAnimator.playTogether(mIconTranslationYForStash.animateToValue(isStashed
+ ? stashTranslation : 0)
.setDuration(duration));
mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration));
@@ -532,6 +572,40 @@
return;
}
+ // If Hotseat is not the top element during animation to/from Launcher, fade in/out a
+ // already stashed Taskbar.
+ boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned()
+ && hasAnyFlag(changedFlags, FLAG_IN_APP);
+ if (isTransientTaskbar) {
+ createTransientAnimToIsStashed(mAnimator, isStashed, duration, animateBg, changedFlags,
+ skipStashAnimation);
+ } else {
+ createAnimToIsStashed(mAnimator, isStashed, duration, animateBg, skipStashAnimation,
+ stashTranslation);
+ }
+
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsStashed = isStashed;
+ onIsStashedChanged(mIsStashed);
+
+ cancelTimeoutIfExists();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+
+ if (!mIsStashed) {
+ tryStartTaskbarTimeout();
+ }
+ }
+ });
+ }
+
+ private void createAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
+ boolean animateBg, boolean skipStashAnimation, float stashTranslation) {
AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
// Not exactly half and may overlap. See [first|second]HalfDurationScale below.
AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
@@ -540,10 +614,6 @@
final float firstHalfDurationScale;
final float secondHalfDurationScale;
- // If Hotseat is not the top element during animation to/from Launcher, fade in/out a
- // already stashed Taskbar.
- boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned()
- && hasAnyFlag(changedFlags, FLAG_IN_APP);
if (isStashed) {
firstHalfDurationScale = 0.75f;
secondHalfDurationScale = 0.5f;
@@ -596,10 +666,6 @@
}
}
- if (DisplayController.isTransientTaskbar(mActivity)) {
- fullLengthAnimatorSet.play(mControllers.taskbarViewController
- .createRevealAnimToIsStashed(isStashed));
- }
fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
.createRevealAnimToIsStashed(isStashed));
// Return the stashed handle to its default scale in case it was changed as part of the
@@ -611,26 +677,73 @@
secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale));
secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale)));
- mAnimator.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
+ as.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
secondHalfAnimatorSet);
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mIsStashed = isStashed;
- onIsStashedChanged(mIsStashed);
- cancelTimeoutIfExists();
+ }
+
+ private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
+ boolean animateBg, int changedFlags, boolean skipStashAnimation) {
+ Interpolator skipInterpolator = null;
+
+ if (isStashed) {
+ if (animateBg) {
+ play(as, mTaskbarBackgroundOffset.animateToValue(1), 0, duration, EMPHASIZED);
+ } else {
+ as.addListener(AnimatorListeners.forEndCallback(
+ () -> mTaskbarBackgroundOffset.updateValue(1)));
}
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
+ long alphaStartDelay = duration == 0 ? 0 : (changedFlags == FLAG_IN_APP)
+ ? TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY
+ : TASKBAR_STASH_ALPHA_START_DELAY;
+ long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION;
+ play(as, mIconAlphaForStash.animateToValue(0), alphaStartDelay, alphaDuration, LINEAR);
+ play(as, mTaskbarStashedHandleAlpha.animateToValue(1), alphaStartDelay,
+ Math.max(0, duration - alphaStartDelay), LINEAR);
- if (!mIsStashed) {
- tryStartTaskbarTimeout();
- }
+ if (skipStashAnimation) {
+ skipInterpolator = INSTANT;
}
- });
+ } else {
+ if (animateBg) {
+ play(as, mTaskbarBackgroundOffset.animateToValue(0), 0, duration, EMPHASIZED);
+ } else {
+ as.addListener(AnimatorListeners.forEndCallback(
+ () -> mTaskbarBackgroundOffset.updateValue(0)));
+ }
+
+ long alphaStartDelay = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_START_DELAY;
+ long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION;
+ play(as, mIconAlphaForStash.animateToValue(1), alphaStartDelay, alphaDuration, LINEAR);
+ play(as, mTaskbarStashedHandleAlpha.animateToValue(0), 0, alphaDuration, LINEAR);
+
+ if (skipStashAnimation) {
+ skipInterpolator = FINAL_FRAME;
+ }
+ }
+ play(as, mControllers.taskbarViewController
+ .createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
+
+ if (skipInterpolator != null) {
+ as.setInterpolator(skipInterpolator);
+ }
+
+ play(as, mControllers.stashedHandleViewController
+ .createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
+
+ // Return the stashed handle to its default scale in case it was changed as part of the
+ // feedforward hint. Note that the reveal animation above also visually scales it.
+ as.play(mTaskbarStashedHandleHintScale.animateToValue(1f)
+ .setDuration(isStashed ? duration / 2 : duration));
+ }
+
+ private static void play(AnimatorSet as, Animator a, long startDelay, long duration,
+ Interpolator interpolator) {
+ a.setDuration(duration);
+ a.setStartDelay(startDelay);
+ a.setInterpolator(interpolator);
+ as.play(a);
}
private void addJankMonitorListener(AnimatorSet animator, boolean expanding) {
@@ -712,7 +825,6 @@
}
}
-
/**
* Returns an animator which applies the latest state if mIsStashed is changed, or {@code null}
* otherwise.
@@ -845,6 +957,8 @@
if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAGS_IN_APP)) {
notifyStashChange(/* visible */ hasAnyFlag(FLAGS_IN_APP),
/* stashed */ isStashedInApp());
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER, !isInApp());
}
if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
if (hasAnyFlag(FLAG_STASHED_IN_APP_MANUAL)) {
@@ -932,7 +1046,6 @@
appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL");
appendFlag(sj, flags, FLAG_STASHED_IN_SYSUI_STATE, "FLAG_STASHED_IN_SYSUI_STATE");
- appendFlag(sj, flags, FLAG_STASHED_IN_APP_EMPTY, "FLAG_STASHED_IN_APP_EMPTY");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
appendFlag(sj, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE");
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 80f030f..a6b2a8a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -113,7 +113,8 @@
return;
}
reset();
- if (mControllers.taskbarStashController.isTaskbarVisibleAndNotStashing()) {
+ if (mControllers.taskbarStashController.isInApp()
+ && mControllers.taskbarStashController.isTaskbarVisibleAndNotStashing()) {
mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
}
}));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index bfdf156..b552e9b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -17,25 +17,28 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
+
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
-import com.android.systemui.shared.recents.model.Task;
import java.io.PrintWriter;
-import java.util.function.Consumer;
/**
* Base class for providing different taskbar UI
@@ -72,8 +75,19 @@
protected void onStashedInAppChanged() { }
+ /**
+ * Called when taskbar icon layout bounds change.
+ */
+ protected void onIconLayoutBoundsChanged() { }
+
/** Called when an icon is launched. */
- public void onTaskbarIconLaunched(ItemInfo item) { }
+ @CallSuper
+ public void onTaskbarIconLaunched(ItemInfo item) {
+ // When launching from Taskbar, e.g. from Overview, set FLAG_IN_APP immediately instead of
+ // waiting for onPause, to reduce potential visual noise during the app open transition.
+ mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, true);
+ mControllers.taskbarStashController.applyState();
+ }
public View getRootView() {
return mControllers.taskbarActivityContext.getDragLayer();
@@ -103,7 +117,7 @@
public void onExpandPip() {
if (mControllers != null) {
final TaskbarStashController stashController = mControllers.taskbarStashController;
- stashController.updateStateForFlag(TaskbarStashController.FLAG_IN_APP, true);
+ stashController.updateStateForFlag(FLAG_IN_APP, true);
stashController.applyState();
}
}
@@ -174,9 +188,13 @@
if (recentsView == null) {
return;
}
- recentsView.findLastActiveTaskAndRunCallback(
- splitSelectSource.intent.getComponent(),
- (Consumer<Task>) foundTask -> {
+
+ ComponentKey componentToBeStaged = new ComponentKey(
+ splitSelectSource.itemInfo.getTargetComponent(),
+ splitSelectSource.itemInfo.user);
+ recentsView.getSplitSelectController().findLastActiveTaskAndRunCallback(
+ componentToBeStaged,
+ foundTask -> {
splitSelectSource.alreadyRunningTaskId = foundTask == null
? INVALID_TASK_ID
: foundTask.key.id;
@@ -191,9 +209,10 @@
*/
public void triggerSecondAppForSplit(ItemInfoWithIcon info, Intent intent, View startingView) {
RecentsView recents = getRecentsView();
- recents.findLastActiveTaskAndRunCallback(
- info.getTargetComponent(),
- (Consumer<Task>) foundTask -> {
+ ComponentKey secondAppComponent = new ComponentKey(info.getTargetComponent(), info.user);
+ recents.getSplitSelectController().findLastActiveTaskAndRunCallback(
+ secondAppComponent,
+ foundTask -> {
if (foundTask != null) {
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
// TODO (b/266482558): This additional null check is needed because there
@@ -228,4 +247,34 @@
}
);
}
+
+ /**
+ * Opens the Keyboard Quick Switch View.
+ *
+ * This will set the focus to the first task from the right (from the left in RTL)
+ */
+ public void openQuickSwitchView() {
+ mControllers.keyboardQuickSwitchController.openQuickSwitchView();
+ }
+
+ /**
+ * Launches the focused task and closes the Keyboard Quick Switch View.
+ *
+ * If the overlay or view are closed, or the overview task is focused, then Overview is
+ * launched. If the overview task is launched, then the first hidden task is focused.
+ *
+ * @return the index of what task should be focused in ; -1 iff Overview shouldn't be launched
+ */
+ public int launchFocusedTask() {
+ int focusedTaskIndex = mControllers.keyboardQuickSwitchController.launchFocusedTask();
+ mControllers.keyboardQuickSwitchController.closeQuickSwitchView();
+ return focusedTaskIndex;
+ }
+
+ /**
+ * Launches the focused task in splitscreen.
+ *
+ * No-op if the view is not yet open.
+ */
+ public void launchSplitTasks(@NonNull View taskview, @NonNull GroupTask groupTask) { }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 38351a9..0b275a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -58,6 +58,8 @@
private static final String TAG = TaskbarView.class.getSimpleName();
private static final float TASKBAR_BACKGROUND_LUMINANCE = 0.30f;
+ private static final Rect sTmpRect = new Rect();
+
public int mThemeIconsBackground;
private final int[] mTempOutLocation = new int[2];
@@ -74,9 +76,6 @@
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
- // Prevents dispatching touches to children if true
- private boolean mTouchEnabled = true;
-
// Only non-null when the corresponding Folder is open.
private @Nullable FolderIcon mLeaveBehindFolderIcon;
@@ -88,6 +87,10 @@
private View mQsb;
+ private float mTransientTaskbarMinWidth;
+
+ private float mTransientTaskbarAllAppsButtonTranslationXOffset;
+
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -107,7 +110,14 @@
mActivityContext = ActivityContext.lookupContext(context);
mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
Resources resources = getResources();
+ boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext);
mIsRtl = Utilities.isRtl(resources);
+ mTransientTaskbarMinWidth = mContext.getResources().getDimension(
+ R.dimen.transient_taskbar_min_width);
+ mTransientTaskbarAllAppsButtonTranslationXOffset =
+ resources.getDimension(isTransientTaskbar
+ ? R.dimen.transient_taskbar_all_apps_button_translation_x_offset
+ : R.dimen.taskbar_all_apps_button_translation_x_offset);
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
@@ -124,14 +134,15 @@
mThemeIconsBackground = calculateThemeIconsBackground();
- if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()
- && !mActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) {
+ if (!mActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) {
mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
.inflate(R.layout.taskbar_all_apps_button, this, false);
- mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ mAllAppsButton.setIconDrawable(resources.getDrawable(isTransientTaskbar
+ ? R.drawable.ic_transient_taskbar_all_apps_button
+ : R.drawable.ic_taskbar_all_apps_button));
mAllAppsButton.setScaleX(mIsRtl ? -1 : 1);
- mAllAppsButton.setForegroundTint(mActivityContext.getColor(
- DisplayController.isTransientTaskbar(mActivityContext)
+ mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ mAllAppsButton.setForegroundTint(mActivityContext.getColor(isTransientTaskbar
? R.color.all_apps_button_color
: R.color.all_apps_button_color_dark));
@@ -275,9 +286,12 @@
}
if (mAllAppsButton != null) {
+ mAllAppsButton.setTranslationXForTaskbarAllAppsIcon(getChildCount() > 0
+ ? mTransientTaskbarAllAppsButtonTranslationXOffset : 0f);
addView(mAllAppsButton, mIsRtl ? getChildCount() : 0);
- if (mTaskbarDivider != null) {
+ // if only all apps button present, don't include divider view.
+ if (mTaskbarDivider != null && getChildCount() > 1) {
addView(mTaskbarDivider, mIsRtl ? (getChildCount() - 1) : 1);
}
}
@@ -319,6 +333,11 @@
int count = getChildCount();
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int spaceNeeded = getIconLayoutWidth();
+ // We are removing the margin from taskbar divider item in taskbar,
+ // so remove it from spacing also.
+ if (FeatureFlags.ENABLE_TASKBAR_PINNING.get() && count > 1) {
+ spaceNeeded -= mIconTouchSize;
+ }
int navSpaceNeeded = deviceProfile.hotseatBarEndOffset;
boolean layoutRtl = isLayoutRtl();
int iconEnd = right - (right - left - spaceNeeded) / 2;
@@ -331,6 +350,9 @@
(right - navSpaceNeeded) - iconEnd;
iconEnd += offset;
}
+
+ sTmpRect.set(mIconLayoutBounds);
+
// Layout the children
mIconLayoutBounds.right = iconEnd;
mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
@@ -362,15 +384,19 @@
iconEnd = iconStart - mItemMarginLeftRight;
}
}
- mIconLayoutBounds.left = iconEnd;
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (!mTouchEnabled) {
- return true;
+ mIconLayoutBounds.left = iconEnd;
+
+ if (mIconLayoutBounds.right - mIconLayoutBounds.left < mTransientTaskbarMinWidth) {
+ int center = mIconLayoutBounds.centerX();
+ int distanceFromCenter = (int) mTransientTaskbarMinWidth / 2;
+ mIconLayoutBounds.right = center + distanceFromCenter;
+ mIconLayoutBounds.left = center - distanceFromCenter;
}
- return super.dispatchTouchEvent(ev);
+
+ if (!sTmpRect.equals(mIconLayoutBounds)) {
+ mControllerCallbacks.notifyIconLayoutBoundsChanged();
+ }
}
@Override
@@ -381,9 +407,6 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (!mTouchEnabled) {
- return true;
- }
if (mIconLayoutBounds.left <= event.getX()
&& event.getX() <= mIconLayoutBounds.right
&& !DisplayController.isTransientTaskbar(mActivityContext)) {
@@ -404,11 +427,6 @@
return super.onTouchEvent(event);
}
- public void setTouchesEnabled(boolean touchEnabled) {
- this.mTouchEnabled = touchEnabled;
- mControllerCallbacks.clearTouchInProgress();
- }
-
/**
* Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
* touch bounds.
@@ -519,6 +537,7 @@
/**
* Finds the first icon to match one of the given matchers, from highest to lowest priority.
+ *
* @return The first match, or All Apps button if no match was found.
*/
public View getFirstMatch(Predicate<ItemInfo>... matchers) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 9824fe0..ac92374 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.anim.AnimatedFloat.VALUE;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
@@ -28,6 +29,7 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.graphics.Rect;
@@ -199,14 +201,6 @@
}
/**
- * Should be called when the IME visibility changes, so we can make Taskbar not steal touches.
- */
- public void setImeIsVisible(boolean isImeVisible) {
- mTaskbarView.setTouchesEnabled(!isImeVisible
- || DisplayController.isTransientTaskbar(mActivity));
- }
-
- /**
* Should be called when the recents button is disabled, so we can hide taskbar icons as well.
*/
public void setRecentsButtonDisabled(boolean isDisabled) {
@@ -312,11 +306,50 @@
*/
public AnimatorSet createRevealAnimToIsStashed(boolean isStashed) {
AnimatorSet as = new AnimatorSet();
- for (int i = mTaskbarView.getChildCount() - 1; i >= 0; i--) {
+
+ Rect stashedBounds = new Rect();
+ mControllers.stashedHandleViewController.getStashedHandleBounds(stashedBounds);
+
+ int numChildren = mTaskbarView.getChildCount();
+ // We do not actually modify the width of the icons, but we will use this width to position
+ // the children to overlay the nav handle.
+ float virtualChildWidth = stashedBounds.width() / (float) numChildren;
+
+ for (int i = numChildren - 1; i >= 0; i--) {
View child = mTaskbarView.getChildAt(i);
- if (child instanceof BubbleTextView) {
- as.play(createRevealAnimForView(child, isStashed));
+
+ if (child == mTaskbarView.getQsb()) {
+ continue;
}
+
+ // Crop the icons to/from the nav handle shape.
+ as.play(createRevealAnimForView(child, isStashed));
+
+ // Translate the icons to/from their locations as the "nav handle."
+ // We look at 'left' and 'right' values to ensure that the children stay within the
+ // bounds of the stashed handle.
+ float iconLeft = child.getLeft();
+ float newLeft = stashedBounds.left + (virtualChildWidth * i);
+ final float croppedTransX;
+ if (iconLeft > newLeft) {
+ float newRight = stashedBounds.right - (virtualChildWidth * (numChildren - 1 - i));
+ croppedTransX = -(child.getLeft() + child.getWidth() - newRight);
+ } else {
+ croppedTransX = newLeft - iconLeft;
+ }
+
+ as.play(ObjectAnimator.ofFloat(child, ICON_REVEAL_TRANSLATE_X, isStashed
+ ? new float[] {croppedTransX}
+ : new float[] {croppedTransX, 0}));
+
+ float croppedTransY = child.getHeight() - stashedBounds.height();
+ as.play(ObjectAnimator.ofFloat(child, ICON_REVEAL_TRANSLATE_Y, isStashed
+ ? new float[] {croppedTransY}
+ : new float[] {croppedTransY, 0}));
+ as.addListener(forEndCallback(() -> {
+ ICON_REVEAL_TRANSLATE_X.set(child, 0f);
+ ICON_REVEAL_TRANSLATE_Y.set(child, 0f);
+ }));
}
return as;
}
@@ -380,8 +413,7 @@
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
int positionInHotseat;
- boolean isAllAppsButton = FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()
- && child == mTaskbarView.getAllAppsButtonView();
+ boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonView();
if (!mIsHotseatIconOnTopWhenAligned) {
// When going to home, the EMPHASIZED interpolator in TaskbarLauncherStateController
// plays iconAlignment to 1 really fast, therefore moving the fading towards the end
@@ -449,7 +481,7 @@
float childCenter = (child.getLeft() + child.getRight()) / 2f;
setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, interpolator);
- setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator);
+ setter.setFloat(child, ICON_TRANSLATE_Y, mTaskbarBottomMargin, interpolator);
setter.setFloat(child, SCALE_PROPERTY, scaleUp, interpolator);
}
@@ -627,17 +659,24 @@
public void clearTouchInProgress() {
mTouchInProgress = false;
}
+
+ /**
+ * Notifies launcher to update icon alignment.
+ */
+ public void notifyIconLayoutBoundsChanged() {
+ mControllers.uiController.onIconLayoutBoundsChanged();
+ }
}
public static final FloatProperty<View> ICON_TRANSLATE_X =
- new FloatProperty<View>("taskbarAligmentTranslateX") {
+ new FloatProperty<View>("taskbarAlignmentTranslateX") {
@Override
public void setValue(View view, float v) {
if (view instanceof BubbleTextView) {
((BubbleTextView) view).setTranslationXForTaskbarAlignmentAnimation(v);
} else if (view instanceof FolderIcon) {
- ((FolderIcon) view).setTranslationForTaskbarAlignmentAnimation(v);
+ ((FolderIcon) view).setTranslationXForTaskbarAlignmentAnimation(v);
} else {
view.setTranslationX(v);
}
@@ -654,4 +693,81 @@
return view.getTranslationX();
}
};
+
+ public static final FloatProperty<View> ICON_TRANSLATE_Y =
+ new FloatProperty<View>("taskbarAlignmentTranslateY") {
+
+ @Override
+ public void setValue(View view, float v) {
+ if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationYForTaskbarAlignmentAnimation(v);
+ } else if (view instanceof FolderIcon) {
+ ((FolderIcon) view).setTranslationYForTaskbarAlignmentAnimation(v);
+ } else {
+ view.setTranslationY(v);
+ }
+ }
+
+ @Override
+ public Float get(View view) {
+ if (view instanceof BubbleTextView) {
+ return ((BubbleTextView) view)
+ .getTranslationYForTaskbarAlignmentAnimation();
+ } else if (view instanceof FolderIcon) {
+ return ((FolderIcon) view).getTranslationYForTaskbarAlignmentAnimation();
+ }
+ return view.getTranslationY();
+ }
+ };
+
+ public static final FloatProperty<View> ICON_REVEAL_TRANSLATE_X =
+ new FloatProperty<View>("taskbarRevealTranslateX") {
+
+ @Override
+ public void setValue(View view, float v) {
+ if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationXForTaskbarRevealAnimation(v);
+ } else if (view instanceof FolderIcon) {
+ ((FolderIcon) view).setTranslationXForTaskbarRevealAnimation(v);
+ } else {
+ view.setTranslationX(v);
+ }
+ }
+
+ @Override
+ public Float get(View view) {
+ if (view instanceof BubbleTextView) {
+ return ((BubbleTextView) view).getTranslationXForTaskbarRevealAnimation();
+ } else if (view instanceof FolderIcon) {
+ return ((FolderIcon) view).getTranslationXForTaskbarRevealAnimation();
+ }
+ return view.getTranslationX();
+ }
+ };
+
+ public static final FloatProperty<View> ICON_REVEAL_TRANSLATE_Y =
+ new FloatProperty<View>("taskbarRevealTranslateY") {
+
+ @Override
+ public void setValue(View view, float v) {
+ if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationYForTaskbarRevealAnimation(v);
+ } else if (view instanceof FolderIcon) {
+ ((FolderIcon) view).setTranslationYForTaskbarRevealAnimation(v);
+ } else {
+ view.setTranslationY(v);
+ }
+ }
+
+ @Override
+ public Float get(View view) {
+ if (view instanceof BubbleTextView) {
+ return ((BubbleTextView) view).getTranslationYForTaskbarRevealAnimation();
+ } else if (view instanceof FolderIcon) {
+ return ((FolderIcon) view).getTranslationYForTaskbarRevealAnimation();
+ }
+ return view.getTranslationY();
+ }
+ };
+
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/Utilities.java b/quickstep/src/com/android/launcher3/taskbar/Utilities.java
index fda6453..a2b3c96 100644
--- a/quickstep/src/com/android/launcher3/taskbar/Utilities.java
+++ b/quickstep/src/com/android/launcher3/taskbar/Utilities.java
@@ -30,4 +30,18 @@
str.add(flagName);
}
}
+
+ /**
+ * Sets drag, long-click, and split selection behavior on 1P and 3P launchers with Taskbar
+ */
+ static void setOverviewDragState(TaskbarControllers controllers,
+ boolean disallowGlobalDrag, boolean disallowLongClick,
+ boolean allowInitialSplitSelection) {
+ controllers.taskbarDragController.setDisallowGlobalDrag(disallowGlobalDrag);
+ controllers.taskbarDragController.setDisallowLongClick(disallowLongClick);
+ controllers.taskbarAllAppsController.setDisallowGlobalDrag(disallowGlobalDrag);
+ controllers.taskbarAllAppsController.setDisallowLongClick(disallowLongClick);
+ controllers.taskbarPopupController.setAllowInitialSplitSelection(
+ allowInitialSplitSelection);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index 7a5deb7..5eb240e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -35,7 +35,7 @@
* Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. Specifically:
* - We always hide the taskbar icons or stashed handle, whichever is currently showing.
* - For persistent taskbar, we also move the taskbar background to a new window/layer
- * (TYPE_APPLICATION_OVERLAY) which is behind the assistant.
+ * (TYPE_APPLICATION_OVERLAY) which is behind the assistant.
* - For transient taskbar, we hide the real taskbar background (if it's showing).
*/
class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 7a34869..4a95a8f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -20,7 +20,6 @@
import com.android.launcher3.R;
import com.android.launcher3.appprediction.PredictionRowView;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.taskbar.TaskbarControllers;
@@ -54,9 +53,6 @@
/** Initialize the controller. */
public void init(TaskbarControllers controllers, boolean allAppsVisible) {
- if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
- return;
- }
mControllers = controllers;
/*
@@ -70,10 +66,6 @@
/** Updates the current {@link AppInfo} instances. */
public void setApps(AppInfo[] apps, int flags) {
- if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
- return;
- }
-
mApps = apps;
mAppsModelFlags = flags;
if (mAppsView != null) {
@@ -91,10 +83,6 @@
/** Updates the current predictions. */
public void setPredictedApps(List<ItemInfo> predictedApps) {
- if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
- return;
- }
-
mPredictedApps = predictedApps;
if (mAppsView != null) {
mAppsView.getFloatingHeaderView()
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index a82902f..27a4988 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -31,7 +31,7 @@
*
* @property navButtonContainer ViewGroup that holds the 3 navigation buttons.
* @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME
- * dismiss).
+ * dismiss).
* @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
*/
abstract class AbstractNavButtonLayoutter(
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index d91b650..ec64128 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -27,17 +27,45 @@
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
/** Root drag layer for the Taskbar overlay window. */
public class TaskbarOverlayDragLayer extends
BaseDragLayer<TaskbarOverlayContext> implements
ViewTreeObserver.OnComputeInternalInsetsListener {
+ private final List<OnClickListener> mOnClickListeners = new CopyOnWriteArrayList<>();
+ private final TouchController mClickListenerTouchController = new TouchController() {
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ for (OnClickListener listener : mOnClickListeners) {
+ listener.onClick(TaskbarOverlayDragLayer.this);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ for (int i = 0; i < getChildCount(); i++) {
+ if (isEventOverView(getChildAt(i), ev)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
TaskbarOverlayDragLayer(Context context) {
super(context, null, 1);
setClipChildren(false);
@@ -58,7 +86,10 @@
@Override
public void recreateControllers() {
- mControllers = new TouchController[]{mActivity.getDragController()};
+ mControllers = mOnClickListeners.isEmpty()
+ ? new TouchController[]{mActivity.getDragController()}
+ : new TouchController[] {
+ mActivity.getDragController(), mClickListenerTouchController};
}
@Override
@@ -99,6 +130,51 @@
}
/**
+ * Adds the given callback to clicks to this drag layer.
+ * <p>
+ * Clicks are only accepted on this drag layer if they fall within this drag layer's bounds and
+ * outside the bounds of all child views.
+ * <p>
+ * If the click falls within the bounds of a child view, then this callback does not run and
+ * that child can optionally handle it.
+ */
+ private void addOnClickListener(@NonNull OnClickListener listener) {
+ boolean wasEmpty = mOnClickListeners.isEmpty();
+ mOnClickListeners.add(listener);
+ if (wasEmpty) {
+ recreateControllers();
+ }
+ }
+
+ /**
+ * Removes the given on click callback.
+ * <p>
+ * No-op if the callback was never added.
+ */
+ private void removeOnClickListener(@NonNull OnClickListener listener) {
+ boolean wasEmpty = mOnClickListeners.isEmpty();
+ mOnClickListeners.remove(listener);
+ if (!wasEmpty && mOnClickListeners.isEmpty()) {
+ recreateControllers();
+ }
+ }
+
+ /**
+ * Queues the given callback on the next click on this drag layer.
+ * <p>
+ * Once run, this callback is immediately removed.
+ */
+ public void runOnClickOnce(@NonNull OnClickListener listener) {
+ addOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ listener.onClick(v);
+ removeOnClickListener(this);
+ }
+ });
+ }
+
+ /**
* Taskbar automatically stashes when opening all apps, but we don't report the insets as
* changing to avoid moving the underlying app. But internally, the apps view should still
* layout according to the stashed insets rather than the unstashed insets. So this method
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
deleted file mode 100644
index c46809a..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.provider.DeviceConfig;
-
-import com.android.launcher3.config.FeatureFlags.DebugFlag;
-
-@TargetApi(Build.VERSION_CODES.P)
-public class DeviceFlag extends DebugFlag {
-
- public static final String NAMESPACE_LAUNCHER = "launcher";
-
- private final boolean mDefaultValueInCode;
-
- public DeviceFlag(String key, boolean defaultValue, String description) {
- super(key, getDeviceValue(key, defaultValue), description);
- mDefaultValueInCode = defaultValue;
- }
-
- @Override
- protected StringBuilder appendProps(StringBuilder src) {
- return super.appendProps(src).append(", mDefaultValueInCode=").append(mDefaultValueInCode);
- }
-
- @Override
- public boolean get() {
- // Override this method in order to let Robolectric ShadowDeviceFlag to stub it.
- return super.get();
- }
-
- protected static boolean getDeviceValue(String key, boolean defaultValue) {
- return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValue);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index bf0f8f7..25207d4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -124,7 +124,7 @@
int shadowSize = context.getResources().getDimensionPixelSize(
R.dimen.blur_size_thin_outline);
mShadowFilter = new BlurMaskFilter(shadowSize, BlurMaskFilter.Blur.OUTER);
- mShapePath = GraphicsUtils.getShapePath(mNormalizedIconSize);
+ mShapePath = GraphicsUtils.getShapePath(context, mNormalizedIconSize);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 5537878..a56300a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -34,7 +35,7 @@
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_WIDGET_PICKER_DEPTH;
+import static com.android.launcher3.config.FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
@@ -48,6 +49,7 @@
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -66,6 +68,7 @@
import android.graphics.RectF;
import android.hardware.SensorManager;
import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.display.DisplayManager;
import android.media.permission.SafeCloseable;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -134,6 +137,7 @@
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NavigationMode;
@@ -141,6 +145,7 @@
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.PendingSplitSelectInfo;
import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
import com.android.launcher3.util.TouchController;
@@ -150,6 +155,7 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LauncherUnfoldAnimationController;
import com.android.quickstep.util.ProxyScreenStatusProvider;
import com.android.quickstep.util.QuickstepOnboardingPrefs;
@@ -164,13 +170,14 @@
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.unfold.RemoteUnfoldSharedComponent;
import com.android.systemui.unfold.UnfoldSharedComponent;
import com.android.systemui.unfold.UnfoldTransitionFactory;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
+import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver;
import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider;
import com.android.systemui.unfold.system.DeviceStateManagerFoldProvider;
import com.android.systemui.unfold.updates.RotationChangeProvider;
@@ -180,7 +187,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -204,7 +210,6 @@
// Will be updated when dragging from taskbar.
private @Nullable DragOptions mNextWorkspaceDragOptions = null;
private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
- private @Nullable RotationChangeProvider mRotationChangeProvider;
private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
private SplitSelectStateController mSplitSelectStateController;
@@ -229,7 +234,8 @@
RecentsView overviewPanel = getOverviewPanel();
mSplitSelectStateController =
new SplitSelectStateController(this, mHandler, getStateManager(),
- getDepthController(), getStatsLogManager());
+ getDepthController(), getStatsLogManager(),
+ SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this));
overviewPanel.init(mActionsView, mSplitSelectStateController);
mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this,
mSplitSelectStateController);
@@ -238,7 +244,7 @@
mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
- mAppTransitionManager = new QuickstepTransitionManager(this);
+ mAppTransitionManager = buildAppTransitionManager();
mAppTransitionManager.registerRemoteAnimations();
mAppTransitionManager.registerRemoteTransitions();
@@ -247,8 +253,7 @@
mDesktopVisibilityController = new DesktopVisibilityController(this);
mHotseatPredictionController = new HotseatPredictionController(this);
- mEnableWidgetDepth = ENABLE_WIDGET_PICKER_DEPTH.get()
- && SystemProperties.getBoolean("ro.launcher.depth.widget", true);
+ mEnableWidgetDepth = SystemProperties.getBoolean("ro.launcher.depth.widget", true);
getWorkspace().addOverlayCallback(progress ->
onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX));
}
@@ -307,6 +312,13 @@
return mHotseatPredictionController;
}
+ /**
+ * Builds the {@link QuickstepTransitionManager} instance to use for managing transitions.
+ */
+ protected QuickstepTransitionManager buildAppTransitionManager() {
+ return new QuickstepTransitionManager(this);
+ }
+
@Override
protected QuickstepOnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
return new QuickstepOnboardingPrefs(this, sharedPrefs);
@@ -564,11 +576,14 @@
@Override
public void startSplitSelection(SplitSelectSource splitSelectSource) {
RecentsView recentsView = getOverviewPanel();
+ ComponentKey componentToBeStaged = new ComponentKey(
+ splitSelectSource.itemInfo.getTargetComponent(),
+ splitSelectSource.itemInfo.user);
// Check if there is already an instance of this app running, if so, initiate the split
// using that.
- recentsView.findLastActiveTaskAndRunCallback(
- splitSelectSource.intent.getComponent(),
- (Consumer<Task>) foundTask -> {
+ mSplitSelectStateController.findLastActiveTaskAndRunCallback(
+ componentToBeStaged,
+ foundTask -> {
splitSelectSource.alreadyRunningTaskId = foundTask == null
? INVALID_TASK_ID
: foundTask.key.id;
@@ -582,8 +597,7 @@
}
/** TODO(b/266482558) Migrate into SplitSelectStateController or someplace split specific. */
- private void startSplitToHome(
- SplitSelectSource source) {
+ private void startSplitToHome(SplitSelectSource source) {
AbstractFloatingView.closeAllOpenViews(this);
int splitPlaceholderSize = getResources().getDimensionPixelSize(
R.dimen.split_placeholder_size);
@@ -591,14 +605,14 @@
R.dimen.split_placeholder_inset);
Rect tempRect = new Rect();
- SplitSelectStateController controller = getSplitSelectStateController();
- controller.setInitialTaskSelect(source.intent, source.position.stagePosition,
- source.itemInfo, source.splitEvent, source.alreadyRunningTaskId);
+ mSplitSelectStateController.setInitialTaskSelect(source.intent,
+ source.position.stagePosition, source.itemInfo, source.splitEvent,
+ source.alreadyRunningTaskId);
RecentsView recentsView = getOverviewPanel();
recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds(
splitPlaceholderSize, splitPlaceholderInset, getDeviceProfile(),
- controller.getActiveSplitStagePosition(), tempRect);
+ mSplitSelectStateController.getActiveSplitStagePosition(), tempRect);
PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration());
RectF startingTaskRect = new RectF();
@@ -607,12 +621,12 @@
floatingTaskView.setAlpha(1);
floatingTaskView.addStagingAnimation(anim, startingTaskRect, tempRect,
false /* fadeWithThumbnail */, true /* isStagedTask */);
- controller.setFirstFloatingTaskView(floatingTaskView);
+ mSplitSelectStateController.setFirstFloatingTaskView(floatingTaskView);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
getDragLayer().removeView(floatingTaskView);
- controller.resetState();
+ mSplitSelectStateController.resetState();
}
});
anim.buildAnim().start();
@@ -800,7 +814,7 @@
@Override
public void setResumed() {
- if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
DesktopVisibilityController controller = mDesktopVisibilityController;
if (controller != null && controller.areFreeformTasksVisible()
&& !controller.isGestureInProgress()) {
@@ -844,38 +858,80 @@
private void initUnfoldTransitionProgressProvider() {
final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
if (config.isEnabled()) {
- UnfoldSharedComponent unfoldComponent =
- UnfoldTransitionFactory.createUnfoldSharedComponent(
- /* context= */ this,
- config,
- ProxyScreenStatusProvider.INSTANCE,
- new DeviceStateManagerFoldProvider(
- getSystemService(DeviceStateManager.class), /* context */this),
- new ActivityManagerActivityTypeProvider(
- getSystemService(ActivityManager.class)),
- getSystemService(SensorManager.class),
- getMainThreadHandler(),
- getMainExecutor(),
- /* backgroundExecutor= */ UI_HELPER_EXECUTOR,
- /* tracingTagPrefix= */ "launcher",
- WindowManagerGlobal.getWindowManagerService()
- );
+ if (RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
+ initRemotelyCalculatedUnfoldAnimation(config);
+ } else {
+ initLocallyCalculatedUnfoldAnimation(config);
+ }
- mUnfoldTransitionProgressProvider = unfoldComponent.getUnfoldTransitionProvider()
- .orElseThrow(() -> new IllegalStateException(
- "Trying to create UnfoldTransitionProgressProvider when the "
- + "transition is disabled"));
-
- mRotationChangeProvider = unfoldComponent.getRotationChangeProvider();
- mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController(
- /* launcher= */ this,
- getWindowManager(),
- mUnfoldTransitionProgressProvider,
- mRotationChangeProvider
- );
}
}
+ /** Registers hinge angle listener and calculates the animation progress in this process. */
+ private void initLocallyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) {
+ UnfoldSharedComponent unfoldComponent =
+ UnfoldTransitionFactory.createUnfoldSharedComponent(
+ /* context= */ this,
+ config,
+ ProxyScreenStatusProvider.INSTANCE,
+ new DeviceStateManagerFoldProvider(
+ getSystemService(DeviceStateManager.class), /* context= */ this),
+ new ActivityManagerActivityTypeProvider(
+ getSystemService(ActivityManager.class)),
+ getSystemService(SensorManager.class),
+ getMainThreadHandler(),
+ getMainExecutor(),
+ /* backgroundExecutor= */ UI_HELPER_EXECUTOR,
+ /* tracingTagPrefix= */ "launcher",
+ getSystemService(DisplayManager.class)
+ );
+
+ mUnfoldTransitionProgressProvider = unfoldComponent.getUnfoldTransitionProvider()
+ .orElseThrow(() -> new IllegalStateException(
+ "Trying to create UnfoldTransitionProgressProvider when the "
+ + "transition is disabled"));
+
+ initUnfoldAnimationController(mUnfoldTransitionProgressProvider,
+ unfoldComponent.getRotationChangeProvider());
+ }
+
+ /** Receives animation progress from sysui process. */
+ private void initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) {
+ RemoteUnfoldSharedComponent unfoldComponent =
+ UnfoldTransitionFactory.createRemoteUnfoldSharedComponent(
+ /* context= */ this,
+ config,
+ getMainExecutor(),
+ getMainThreadHandler(),
+ /* backgroundExecutor= */ UI_HELPER_EXECUTOR,
+ /* tracingTagPrefix= */ "launcher",
+ getSystemService(DisplayManager.class)
+ );
+
+ final RemoteUnfoldTransitionReceiver remoteUnfoldTransitionProgressProvider =
+ unfoldComponent.getRemoteTransitionProgress().orElseThrow(
+ () -> new IllegalStateException(
+ "Trying to create getRemoteTransitionProgress when the transition "
+ + "is disabled"));
+ mUnfoldTransitionProgressProvider = remoteUnfoldTransitionProgressProvider;
+
+ SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(
+ remoteUnfoldTransitionProgressProvider);
+
+ initUnfoldAnimationController(mUnfoldTransitionProgressProvider,
+ unfoldComponent.getRotationChangeProvider());
+ }
+
+ private void initUnfoldAnimationController(UnfoldTransitionProgressProvider progressProvider,
+ RotationChangeProvider rotationChangeProvider) {
+ mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController(
+ /* launcher= */ this,
+ getWindowManager(),
+ progressProvider,
+ rotationChangeProvider
+ );
+ }
+
public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) {
mTaskbarUIController = taskbarUIController;
}
@@ -997,7 +1053,12 @@
activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER,
mLastTouchUpTime);
}
- activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
+ if (item != null && item.itemType == ITEM_TYPE_SEARCH_ACTION) {
+ activityOptions.options.setSplashScreenStyle(
+ SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
+ } else {
+ activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
+ }
activityOptions.options.setLaunchDisplayId(
(v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
: Display.DEFAULT_DISPLAY);
@@ -1097,14 +1158,12 @@
// Launcher to first restore into Overview state, wait for the relevant tasks and icons to
// load in, and then proceed to OverviewSplitSelect.
if (isInState(OVERVIEW_SPLIT_SELECT)) {
- SplitSelectStateController splitSelectStateController =
- ((RecentsView) getOverviewPanel()).getSplitSelectController();
// Launcher will restart in Overview and then transition to OverviewSplitSelect.
outState.putIBinder(PENDING_SPLIT_SELECT_INFO, ObjectWrapper.wrap(
new PendingSplitSelectInfo(
- splitSelectStateController.getInitialTaskId(),
- splitSelectStateController.getActiveSplitStagePosition(),
- splitSelectStateController.getSplitEvent())
+ mSplitSelectStateController.getInitialTaskId(),
+ mSplitSelectStateController.getActiveSplitStagePosition(),
+ mSplitSelectStateController.getSplitEvent())
));
outState.putInt(RUNTIME_STATE, OVERVIEW.ordinal);
}
@@ -1150,6 +1209,32 @@
getDeviceProfile().toSmallString());
}
+ /**
+ * Launches the given {@link GroupTask} in splitscreen.
+ *
+ * If the second split task is missing, launches the first task normally.
+ */
+ public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
+ if (groupTask.task2 == null) {
+ UI_HELPER_EXECUTOR.execute(() ->
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(
+ groupTask.task1.key,
+ getActivityLaunchOptions(taskView, null).options));
+ return;
+ }
+ mSplitSelectStateController.launchTasks(
+ groupTask.task1.key.id,
+ groupTask.task2.key.id,
+ SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
+ /* callback= */ success -> {},
+ /* freezeTaskList= */ true,
+ groupTask.mSplitBounds == null
+ ? DEFAULT_SPLIT_RATIO
+ : groupTask.mSplitBounds.appsStackedVertically
+ ? groupTask.mSplitBounds.topTaskPercent
+ : groupTask.mSplitBounds.leftTaskPercent);
+ }
+
private static final class LauncherTaskViewController extends
TaskViewTouchController<Launcher> {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index a8edd51..278a45a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -32,6 +32,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -41,13 +42,21 @@
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import java.util.function.IntConsumer;
/**
* {@link LauncherWidgetHolder} that puts the app widget host in the background
*/
public final class QuickstepWidgetHolder extends LauncherWidgetHolder {
+
+ private static final UpdateKey<AppWidgetProviderInfo> KEY_PROVIDER_UPDATE =
+ AppWidgetHostView::onUpdateProviderInfo;
+ private static final UpdateKey<RemoteViews> KEY_VIEWS_UPDATE =
+ AppWidgetHostView::updateAppWidget;
+ private static final UpdateKey<Integer> KEY_VIEW_DATA_CHANGED =
+ AppWidgetHostView::onViewDataChanged;
+
private static final List<QuickstepWidgetHolder> sHolders = new ArrayList<>();
private static final SparseArray<QuickstepWidgetHolderListener> sListeners =
new SparseArray<>();
@@ -59,6 +68,8 @@
private final @NonNull IntConsumer mAppWidgetRemovedCallback;
private final ArrayList<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>();
+ // Map to all pending updated keyed with appWidgetId;
+ private final SparseArray<PendingUpdate> mPendingUpdateMap = new SparseArray<>();
@Thunk
QuickstepWidgetHolder(@NonNull Context context,
@@ -90,6 +101,57 @@
return sWidgetHost;
}
+ @Override
+ protected void updateDeferredView() {
+ super.updateDeferredView();
+ int count = mPendingUpdateMap.size();
+ for (int i = 0; i < count; i++) {
+ int widgetId = mPendingUpdateMap.keyAt(i);
+ QuickstepWidgetHolderListener listener = sListeners.get(widgetId);
+ if (listener == null) {
+ continue;
+ }
+ AppWidgetHostView view = listener.mView.get(this);
+ if (view == null) {
+ continue;
+ }
+ PendingUpdate pendingUpdate = mPendingUpdateMap.valueAt(i);
+ if (pendingUpdate == null) {
+ continue;
+ }
+ if (pendingUpdate.providerInfo != null) {
+ KEY_PROVIDER_UPDATE.accept(view, pendingUpdate.providerInfo);
+ }
+ if (pendingUpdate.remoteViews != null) {
+ KEY_VIEWS_UPDATE.accept(view, pendingUpdate.remoteViews);
+ }
+ pendingUpdate.changedViews.forEach(
+ viewId -> KEY_VIEW_DATA_CHANGED.accept(view, viewId));
+ }
+ mPendingUpdateMap.clear();
+ }
+
+ private <T> void addPendingAction(int widgetId, UpdateKey<T> key, T data) {
+ PendingUpdate pendingUpdate = mPendingUpdateMap.get(widgetId);
+ if (pendingUpdate == null) {
+ pendingUpdate = new PendingUpdate();
+ mPendingUpdateMap.put(widgetId, pendingUpdate);
+ }
+
+ if (KEY_PROVIDER_UPDATE.equals(key)) {
+ // For provider change, remove all updates
+ pendingUpdate.providerInfo = (AppWidgetProviderInfo) data;
+ pendingUpdate.remoteViews = null;
+ pendingUpdate.changedViews.clear();
+ } else if (KEY_VIEWS_UPDATE.equals(key)) {
+ // For views update, remove all previous updates, except the provider
+ pendingUpdate.remoteViews = (RemoteViews) data;
+ pendingUpdate.changedViews.clear();
+ } else if (KEY_VIEW_DATA_CHANGED.equals(key)) {
+ pendingUpdate.changedViews.add((Integer) data);
+ }
+ }
+
/**
* Delete the specified app widget from the host
* @param appWidgetId The ID of the app widget to be deleted
@@ -108,6 +170,12 @@
sHolders.remove(this);
}
+ @Override
+ protected boolean shouldListen(int flags) {
+ return (flags & (FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED))
+ == (FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED);
+ }
+
/**
* Add a listener that is triggered when the providers of the widgets are changed
* @param listener The listener that notifies when the providers changed
@@ -163,7 +231,7 @@
QuickstepWidgetHolderListener listener = sListeners.get(appWidgetId);
if (listener == null) {
- listener = new QuickstepWidgetHolderListener(this, widgetView);
+ listener = new QuickstepWidgetHolderListener(appWidgetId, this, widgetView);
sWidgetHost.setListener(appWidgetId, listener);
sListeners.put(appWidgetId, listener);
} else {
@@ -185,14 +253,17 @@
private static class QuickstepWidgetHolderListener
implements AppWidgetHost.AppWidgetHostListener {
+
@NonNull
private final Map<QuickstepWidgetHolder, AppWidgetHostView> mView = new WeakHashMap<>();
- @Nullable
- private RemoteViews mRemoteViews = null;
+ private final int mWidgetId;
- QuickstepWidgetHolderListener(@NonNull QuickstepWidgetHolder holder,
+ @Nullable private RemoteViews mRemoteViews = null;
+
+ QuickstepWidgetHolderListener(int widgetId, @NonNull QuickstepWidgetHolder holder,
@NonNull LauncherAppWidgetHostView view) {
+ mWidgetId = widgetId;
mView.put(holder, view);
}
@@ -207,24 +278,30 @@
@WorkerThread
public void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo info) {
mRemoteViews = null;
- executeOnMainExecutor(v -> v.onUpdateProviderInfo(info));
+ executeOnMainExecutor(KEY_PROVIDER_UPDATE, info);
}
@Override
@WorkerThread
public void updateAppWidget(@Nullable RemoteViews views) {
mRemoteViews = views;
- executeOnMainExecutor(v -> v.updateAppWidget(mRemoteViews));
+ executeOnMainExecutor(KEY_VIEWS_UPDATE, mRemoteViews);
}
@Override
@WorkerThread
public void onViewDataChanged(int viewId) {
- executeOnMainExecutor(v -> v.onViewDataChanged(viewId));
+ executeOnMainExecutor(KEY_VIEW_DATA_CHANGED, viewId);
}
- private void executeOnMainExecutor(Consumer<AppWidgetHostView> consumer) {
- MAIN_EXECUTOR.execute(() -> mView.values().forEach(consumer));
+ private <T> void executeOnMainExecutor(UpdateKey<T> key, T data) {
+ MAIN_EXECUTOR.execute(() -> mView.forEach((holder, view) -> {
+ if (holder.isListening()) {
+ key.accept(view, data);
+ } else {
+ holder.addPendingAction(mWidgetId, key, data);
+ }
+ }));
}
}
@@ -267,4 +344,12 @@
return new QuickstepWidgetHolder(context, appWidgetRemovedCallback, interactionHandler);
}
}
+
+ private static class PendingUpdate {
+ public final IntSet changedViews = new IntSet();
+ public AppWidgetProviderInfo providerInfo;
+ public RemoteViews remoteViews;
+ }
+
+ private interface UpdateKey<T> extends BiConsumer<AppWidgetHostView, T> { }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index e8e8328..07fcf48 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -121,8 +121,7 @@
private void handleSplitSelectionState(@NonNull LauncherState toState,
@NonNull PendingAnimation builder, boolean animate) {
if (toState != OVERVIEW_SPLIT_SELECT) {
- // Not going to split, nothing to do but ensure taskviews are at correct offset
- mRecentsView.resetSplitPrimaryScrollOffset();
+ // Not going to split
return;
}
@@ -153,8 +152,6 @@
as.start();
as.end();
}
-
- mRecentsView.applySplitPrimaryScrollOffset();
}
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
new file mode 100644
index 0000000..177a399
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
@@ -0,0 +1,40 @@
+/*
+ * 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.uioverrides.flags;
+
+import com.android.launcher3.config.FeatureFlags.BooleanFlag;
+
+class DebugFlag extends BooleanFlag {
+
+ public final String key;
+ public final String description;
+
+ public final boolean defaultValue;
+
+ boolean mHasBeenChangedAtLeastOnce;
+
+ public DebugFlag(String key, String description, boolean defaultValue, boolean currentValue) {
+ super(currentValue);
+ this.key = key;
+ this.defaultValue = defaultValue;
+ this.description = description;
+ }
+
+ @Override
+ public String toString() {
+ return key + ": defaultValue=" + defaultValue + ", mCurrentValue=" + get();
+ }
+}
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
similarity index 99%
rename from src/com/android/launcher3/settings/DeveloperOptionsFragment.java
rename to quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
index 40fc16e..9384a89 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.settings;
+package com.android.launcher3.uioverrides.flags;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
@@ -63,7 +63,6 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.config.FlagTogglerPrefUi;
import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.OnboardingPrefs;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
new file mode 100644
index 0000000..3900ebb
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.uioverrides.flags;
+
+class DeviceFlag extends DebugFlag {
+
+ private final boolean mDefaultValueInCode;
+
+ public DeviceFlag(String key, String description, boolean defaultValue,
+ boolean currentValue, boolean defaultValueInCode) {
+ super(key, description, defaultValue, currentValue);
+ mDefaultValueInCode = defaultValueInCode;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ", mDefaultValueInCode=" + mDefaultValueInCode;
+ }
+}
diff --git a/src/com/android/launcher3/config/FlagTogglerPrefUi.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
similarity index 93%
rename from src/com/android/launcher3/config/FlagTogglerPrefUi.java
rename to quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
index 2eb6e6d..4ca7e31 100644
--- a/src/com/android/launcher3/config/FlagTogglerPrefUi.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3.config;
+package com.android.launcher3.uioverrides.flags;
import static com.android.launcher3.config.FeatureFlags.FLAGS_PREF_NAME;
@@ -33,7 +33,7 @@
import androidx.preference.SwitchPreference;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags.DebugFlag;
+import com.android.launcher3.config.FeatureFlags;
/**
* Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}.
@@ -50,7 +50,7 @@
@Override
public void putBoolean(String key, boolean value) {
- for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
+ for (DebugFlag flag : FlagsFactory.getDebugFlags()) {
if (flag.key.equals(key)) {
SharedPreferences prefs = mContext.getSharedPreferences(
FLAGS_PREF_NAME, Context.MODE_PRIVATE);
@@ -71,7 +71,7 @@
@Override
public boolean getBoolean(String key, boolean defaultValue) {
- for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
+ for (DebugFlag flag : FlagsFactory.getDebugFlags()) {
if (flag.key.equals(key)) {
return mContext.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
.getBoolean(key, flag.defaultValue);
@@ -93,7 +93,7 @@
// flag with a different value than the default. That way, when we flip flags in
// future, engineers will pick up the new value immediately. To accomplish this, we use a
// custom preference data store.
- for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
+ for (DebugFlag flag : FlagsFactory.getDebugFlags()) {
SwitchPreference switchPreference = new SwitchPreference(mContext);
switchPreference.setKey(flag.key);
switchPreference.setDefaultValue(flag.defaultValue);
@@ -149,11 +149,11 @@
}
private boolean anyChanged() {
- for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
+ for (DebugFlag flag : FlagsFactory.getDebugFlags()) {
if (getFlagStateFromSharedPrefs(flag) != flag.get()) {
return true;
}
}
return false;
}
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
new file mode 100644
index 0000000..84b873d
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -0,0 +1,183 @@
+/*
+ * 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.uioverrides.flags;
+
+import static android.app.ActivityThread.currentApplication;
+
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+import android.util.Log;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags.BooleanFlag;
+import com.android.launcher3.config.FeatureFlags.IntFlag;
+import com.android.launcher3.util.ScreenOnTracker;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper class to create various flags for system build
+ */
+public class FlagsFactory {
+
+ private static final String TAG = "FlagsFactory";
+
+ private static final FlagsFactory INSTANCE = new FlagsFactory();
+ private static final boolean FLAG_AUTO_APPLY_ENABLED = false;
+
+ public static final String FLAGS_PREF_NAME = "featureFlags";
+ public static final String NAMESPACE_LAUNCHER = "launcher";
+
+ private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
+
+
+ private final Set<String> mKeySet = new HashSet<>();
+ private boolean mRestartRequested = false;
+
+ private FlagsFactory() {
+ if (!FLAG_AUTO_APPLY_ENABLED) {
+ return;
+ }
+ DeviceConfig.addOnPropertiesChangedListener(
+ NAMESPACE_LAUNCHER, UI_HELPER_EXECUTOR, this::onPropertiesChanged);
+ }
+
+ /**
+ * Creates a new debug flag
+ */
+ public static BooleanFlag getDebugFlag(
+ int bugId, String key, boolean defaultValue, String description) {
+ if (Utilities.IS_DEBUG_DEVICE) {
+ SharedPreferences prefs = currentApplication()
+ .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
+ boolean currentValue = prefs.getBoolean(key, defaultValue);
+ DebugFlag flag = new DebugFlag(key, description, defaultValue, currentValue);
+ flag.mHasBeenChangedAtLeastOnce = prefs.contains(key);
+ sDebugFlags.add(flag);
+ return flag;
+ } else {
+ return new BooleanFlag(defaultValue);
+ }
+ }
+
+ /**
+ * Creates a new release flag
+ */
+ public static BooleanFlag getReleaseFlag(
+ int bugId, String key, boolean defaultValueInCode, String description) {
+ INSTANCE.mKeySet.add(key);
+ boolean defaultValue = DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValueInCode);
+ if (Utilities.IS_DEBUG_DEVICE) {
+ SharedPreferences prefs = currentApplication()
+ .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
+ boolean currentValue = prefs.getBoolean(key, defaultValue);
+ DebugFlag flag = new DeviceFlag(key, description, defaultValue, currentValue,
+ defaultValueInCode);
+ flag.mHasBeenChangedAtLeastOnce = prefs.contains(key);
+ sDebugFlags.add(flag);
+ return flag;
+ } else {
+ return new BooleanFlag(defaultValue);
+ }
+ }
+
+ /**
+ * Creates a new integer flag. Integer flags are always release flags
+ */
+ public static IntFlag getIntFlag(
+ int bugId, String key, int defaultValueInCode, String description) {
+ INSTANCE.mKeySet.add(key);
+ return new IntFlag(DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, defaultValueInCode));
+ }
+
+ static List<DebugFlag> getDebugFlags() {
+ if (!Utilities.IS_DEBUG_DEVICE) {
+ return Collections.emptyList();
+ }
+ List<DebugFlag> flags;
+ synchronized (sDebugFlags) {
+ flags = new ArrayList<>(sDebugFlags);
+ }
+ flags.sort((f1, f2) -> {
+ // Sort first by any prefs that the user has changed, then alphabetically.
+ int changeComparison = Boolean.compare(
+ f2.mHasBeenChangedAtLeastOnce, f1.mHasBeenChangedAtLeastOnce);
+ return changeComparison != 0
+ ? changeComparison
+ : f1.key.compareToIgnoreCase(f2.key);
+ });
+ return flags;
+ }
+
+ /**
+ * Dumps the current flags state to the print writer
+ */
+ public static void dump(PrintWriter pw) {
+ if (!Utilities.IS_DEBUG_DEVICE) {
+ return;
+ }
+ pw.println("DeviceFlags:");
+ synchronized (sDebugFlags) {
+ for (DebugFlag flag : sDebugFlags) {
+ if (flag instanceof DeviceFlag) {
+ pw.println(" " + flag);
+ }
+ }
+ }
+ pw.println("DebugFlags:");
+ synchronized (sDebugFlags) {
+ for (DebugFlag flag : sDebugFlags) {
+ if (!(flag instanceof DeviceFlag)) {
+ pw.println(" " + flag);
+ }
+ }
+ }
+ }
+
+ private void onPropertiesChanged(Properties properties) {
+ if (!Collections.disjoint(properties.getKeyset(), mKeySet)) {
+ // Schedule a restart
+ if (mRestartRequested) {
+ return;
+ }
+ Log.e(TAG, "Flag changed, scheduling restart");
+ mRestartRequested = true;
+ ScreenOnTracker sot = ScreenOnTracker.INSTANCE.get(currentApplication());
+ if (sot.isScreenOn()) {
+ sot.addListener(this::onScreenOnChanged);
+ } else {
+ onScreenOnChanged(false);
+ }
+ }
+ }
+
+ private void onScreenOnChanged(boolean isOn) {
+ if (mRestartRequested && !isOn) {
+ Log.e(TAG, "Restart requested, killing process");
+ System.exit(0);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 95eb128..e578720 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -24,9 +24,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
@@ -103,10 +101,6 @@
@Override
public int getWorkspaceScrimColor(Launcher launcher) {
- DeviceProfile dp = launcher.getDeviceProfile();
- if (dp.isTaskbarPresentInApps && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
- return launcher.getColor(R.color.taskbar_background);
- }
return Color.TRANSPARENT;
}
@@ -116,6 +110,18 @@
return super.isTaskbarAlignedWithHotseat(launcher);
}
+ @Override
+ public boolean disallowTaskbarGlobalDrag() {
+ // Enable global drag in overview
+ return false;
+ }
+
+ @Override
+ public boolean allowTaskbarInitialSplitSelection() {
+ // Disallow split select from taskbar items in overview
+ return false;
+ }
+
public static float[] getOverviewScaleAndOffsetForBackgroundState(
BaseDraggingActivity activity) {
return new float[] {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 0c49e5f..b9221ee 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -18,12 +18,12 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.Rect;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.views.RecentsView;
/**
@@ -70,13 +70,22 @@
}
}
- public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
- Point taskSize = activity.<RecentsView>getOverviewPanel().getSelectedTaskSize();
- Rect modalTaskSize = new Rect();
- activity.<RecentsView>getOverviewPanel().getModalTaskSize(modalTaskSize);
+ @Override
+ public boolean isTaskbarStashed(Launcher launcher) {
+ if (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
+ return true;
+ }
+ return super.isTaskbarStashed(launcher);
+ }
- float scale = Math.min((float) modalTaskSize.height() / taskSize.y,
- (float) modalTaskSize.width() / taskSize.x);
+ public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
+ RecentsView recentsView = activity.<RecentsView>getOverviewPanel();
+ Rect taskSize = recentsView.getSelectedTaskBounds();
+ Rect modalTaskSize = new Rect();
+ recentsView.getModalTaskSize(modalTaskSize);
+
+ float scale = Math.min((float) modalTaskSize.height() / taskSize.height(),
+ (float) modalTaskSize.width() / taskSize.width());
return new float[] {scale, NO_OFFSET};
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index d075750..d2f9294 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -26,7 +26,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Themes;
import com.android.quickstep.util.LayoutUtils;
@@ -104,13 +103,8 @@
}
@Override
- public boolean isTaskbarStashed(Launcher launcher) {
- return !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get();
- }
-
- @Override
public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
- return !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get();
+ return false;
}
@Override
@@ -124,6 +118,18 @@
}
@Override
+ public boolean disallowTaskbarGlobalDrag() {
+ // Disable global drag in overview
+ return true;
+ }
+
+ @Override
+ public boolean allowTaskbarInitialSplitSelection() {
+ // Allow split select from taskbar items in overview
+ return true;
+ }
+
+ @Override
public String getDescription(Launcher launcher) {
return launcher.getString(R.string.accessibility_recent_apps);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
index 8babd34..3ae221b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
@@ -53,4 +53,9 @@
return SplitAnimationTimings.ABORT_DURATION;
}
}
+
+ @Override
+ public boolean shouldPreserveDataStateOnReapply() {
+ return true;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index b5afda3..df95dc1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -39,6 +39,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -62,6 +63,7 @@
private static final long TRANSLATION_ANIM_MIN_DURATION_MS = 80;
private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f;
+ private final VibratorWrapper mVibratorWrapper;
private final RecentsView mRecentsView;
private final MotionPauseDetector mMotionPauseDetector;
private final float mMotionPauseMinDisplacement;
@@ -82,6 +84,7 @@
mRecentsView = l.getOverviewPanel();
mMotionPauseDetector = new MotionPauseDetector(l);
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
+ mVibratorWrapper = VibratorWrapper.INSTANCE.get(l.getApplicationContext());
}
@Override
@@ -188,6 +191,11 @@
// need to manually set the duration to a reasonable value.
animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */));
}
+ if (FeatureFlags.ENABLE_HAPTICS_ALL_APPS.get() &&
+ ((mFromState == NORMAL && mToState == ALL_APPS)
+ || (mFromState == ALL_APPS && mToState == NORMAL)) && isFling) {
+ mVibratorWrapper.vibrateForDragBump();
+ }
}
private void onMotionPauseDetected() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index f78d9cf..847114a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -76,6 +76,7 @@
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.WorkspaceRevealAnim;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
@@ -164,6 +165,10 @@
if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
return false;
}
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ // TODO(b/268075592): add support for quickswitch to/from desktop
+ return false;
+ }
return true;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index c5383c3..f941b02 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -48,6 +48,7 @@
import com.android.launcher3.util.NavigationMode;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -78,6 +79,10 @@
if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
return false;
}
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ // TODO(b/268075592): add support for quickswitch to/from desktop
+ return false;
+ }
return true;
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b102705..e9385d9 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -50,6 +50,7 @@
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
+import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -181,6 +182,7 @@
if (mActivity != activity) {
return;
}
+ ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
mRecentsView = null;
mActivity = null;
}
@@ -676,7 +678,7 @@
@Override
public void onMotionPauseDetected() {
mHasMotionEverBeenPaused = true;
- maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */);
+ maybeUpdateRecentsAttachedState(true/* animate */, true/* moveRunningTask */);
Optional.ofNullable(mActivityInterface.getTaskbarController())
.ifPresent(TaskbarUIController::startTranslationSpring);
performHapticFeedback();
@@ -694,7 +696,7 @@
}
private void maybeUpdateRecentsAttachedState(boolean animate) {
- maybeUpdateRecentsAttachedState(animate, false /* moveFocusedTask */);
+ maybeUpdateRecentsAttachedState(animate, false /* moveRunningTask */);
}
/**
@@ -704,9 +706,9 @@
*
* Note this method has no effect unless the navigation mode is NO_BUTTON.
* @param animate whether to animate when attaching RecentsView
- * @param moveFocusedTask whether to move focused task to front when attaching
+ * @param moveRunningTask whether to move running task to front when attaching
*/
- private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveFocusedTask) {
+ private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
if (!mDeviceState.isFullyGesturalNavMode() || mRecentsView == null) {
return;
}
@@ -725,11 +727,11 @@
} else {
recentsAttachedToAppWindow = mHasMotionEverBeenPaused || mIsLikelyToStartNewTask;
}
- if (moveFocusedTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow()
+ if (moveRunningTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow()
&& recentsAttachedToAppWindow) {
- // Only move focused task if RecentsView has never been attached before, to avoid
+ // Only move running task if RecentsView has never been attached before, to avoid
// TaskView jumping to new position as we move the tasks.
- mRecentsView.moveFocusedTaskToFront();
+ mRecentsView.moveRunningTaskToFront();
}
mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
@@ -1165,6 +1167,11 @@
return LAST_TASK;
}
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && endTarget == NEW_TASK) {
+ // TODO(b/268075592): add support for quickswitch to/from desktop
+ return LAST_TASK;
+ }
+
return endTarget;
}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 274b686..3e565b3 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
+import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
@@ -51,6 +52,7 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
@@ -62,6 +64,7 @@
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -107,6 +110,20 @@
if (endTarget != null) {
// We were on our way to this state when we got canceled, end there instead.
startState = stateFromGestureEndTarget(endTarget);
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ DesktopVisibilityController controller = getDesktopVisibilityController();
+ if (controller != null && controller.areFreeformTasksVisible()
+ && endTarget == LAST_TASK) {
+ // When we are cancelling the transition and going back to last task, move to
+ // rest state instead when desktop tasks are visible.
+ // If a fullscreen task is visible, launcher goes to normal state when the
+ // activity is stopped. This does not happen when freeform tasks are visible
+ // on top of launcher. Force the launcher state to rest state here.
+ startState = activity.getStateManager().getRestState();
+ // Do not animate the transition
+ activityVisible = false;
+ }
+ }
}
activity.getStateManager().goToState(startState, activityVisible);
}
@@ -214,17 +231,20 @@
/**
* Calculates the taskView size for the provided device configuration.
*/
- public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect) {
- Resources res = context.getResources();
- float maxScale = res.getFloat(R.dimen.overview_max_scale);
+ public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
+ PagedOrientationHandler orientedState) {
if (dp.isTablet) {
- Rect gridRect = new Rect();
- calculateGridSize(dp, gridRect);
-
- calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect);
+ if (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
+ calculateGridTaskSize(context, dp, outRect, orientedState);
+ } else {
+ calculateFocusTaskSize(context, dp, outRect);
+ }
} else {
+ Resources res = context.getResources();
+ float maxScale = res.getFloat(R.dimen.overview_max_scale);
int taskMargin = dp.overviewTaskMarginPx;
- calculateTaskSizeInternal(context, dp,
+ calculateTaskSizeInternal(
+ dp,
dp.overviewTaskThumbnailTopMarginPx,
dp.getOverviewActionsClaimedSpace(),
res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
@@ -234,7 +254,15 @@
}
}
- private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove,
+ private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+ Resources res = context.getResources();
+ float maxScale = res.getFloat(R.dimen.overview_max_scale);
+ Rect gridRect = new Rect();
+ calculateGridSize(dp, gridRect);
+ calculateTaskSizeInternal(dp, gridRect, maxScale, Gravity.CENTER, outRect);
+ }
+
+ private void calculateTaskSizeInternal(DeviceProfile dp, int claimedSpaceAbove,
int claimedSpaceBelow, int minimumHorizontalPadding, float maxScale, int gravity,
Rect outRect) {
Rect insets = dp.getInsets();
@@ -247,10 +275,10 @@
minimumHorizontalPadding,
claimedSpaceBelow);
- calculateTaskSizeInternal(context, dp, potentialTaskRect, maxScale, gravity, outRect);
+ calculateTaskSizeInternal(dp, potentialTaskRect, maxScale, gravity, outRect);
}
- private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
+ private void calculateTaskSizeInternal(DeviceProfile dp,
Rect potentialTaskRect, float maxScale, int gravity, Rect outRect) {
PointF taskDimension = getTaskDimension(dp);
@@ -301,12 +329,15 @@
public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
PagedOrientationHandler orientedState) {
Resources res = context.getResources();
- Rect taskRect = new Rect();
- calculateTaskSize(context, dp, taskRect);
+ Rect potentialTaskRect = new Rect();
+ if (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
+ calculateGridSize(dp, potentialTaskRect);
+ } else {
+ calculateFocusTaskSize(context, dp, potentialTaskRect);
+ }
- float rowHeight =
- (taskRect.height() + dp.overviewTaskThumbnailTopMarginPx - dp.overviewRowSpacing)
- / 2f;
+ float rowHeight = (potentialTaskRect.height() + dp.overviewTaskThumbnailTopMarginPx
+ - dp.overviewRowSpacing) / 2f;
PointF taskDimension = getTaskDimension(dp);
float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y;
@@ -315,20 +346,37 @@
int gravity = Gravity.TOP;
gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
- Gravity.apply(gravity, outWidth, outHeight, taskRect, outRect);
+ Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
+ }
+
+ /**
+ * Calculates the task size for the desktop task
+ */
+ public final void calculateDesktopTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+ calculateFocusTaskSize(context, dp, outRect);
}
/**
* Calculates the modal taskView size for the provided device configuration
*/
- public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
- calculateTaskSize(context, dp, outRect);
- float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
+ public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect,
+ PagedOrientationHandler orientedState) {
+ calculateTaskSize(context, dp, outRect, orientedState);
+ boolean isGridOnlyOverview = dp.isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get();
+ int claimedSpaceBelow = isGridOnlyOverview
+ ? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarSize
+ : (dp.heightPx - outRect.bottom - dp.getInsets().bottom);
+ int minimumHorizontalPadding = 0;
+ if (!isGridOnlyOverview) {
+ float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
+ minimumHorizontalPadding =
+ Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2);
+ }
calculateTaskSizeInternal(
- context, dp,
+ dp,
dp.overviewTaskMarginPx,
- dp.heightPx - outRect.bottom - dp.getInsets().bottom,
- Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2),
+ claimedSpaceBelow,
+ minimumHorizontalPadding,
1f /*maxScale*/,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
outRect);
diff --git a/quickstep/src/com/android/quickstep/BootAwarePreloader.kt b/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
new file mode 100644
index 0000000..35404a9
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.quickstep
+
+import android.content.Context
+import android.util.Log
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.isBootAwareStartupDataEnabled
+import com.android.launcher3.util.LockedUserState
+
+/**
+ * Loads expensive objects in memory before the user is unlocked. This decreases experienced latency
+ * when starting the launcher for the first time after a reboot.
+ */
+object BootAwarePreloader {
+ private const val TAG = "BootAwarePreloader"
+
+ @JvmStatic
+ fun start(context: Context) {
+ val lp = LauncherPrefs.get(context)
+ when {
+ LockedUserState.get(context).isUserUnlocked || !isBootAwareStartupDataEnabled -> {
+ /* No-Op */
+ }
+ lp.isStartupDataMigrated -> {
+ Log.d(TAG, "preloading start up data")
+ LauncherAppState.INSTANCE.get(context)
+ }
+ else -> {
+ Log.d(TAG, "queuing start up data migration to boot aware prefs")
+ LockedUserState.get(context).runOnUserUnlocked {
+ lp.migrateStartupDataToDeviceProtectedStorage()
+ }
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index ae9fb0b..8bb189a 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -61,7 +61,7 @@
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
PagedOrientationHandler orientationHandler) {
- calculateTaskSize(context, dp, outRect);
+ calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) {
return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
} else {
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 7f2886c..ea9f032 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -73,7 +72,7 @@
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
PagedOrientationHandler orientationHandler) {
- calculateTaskSize(context, dp, outRect);
+ calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout()
&& DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 5a09e02..5b85249 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -24,14 +24,20 @@
import android.os.Build;
import android.os.SystemClock;
import android.os.Trace;
+import android.view.View;
import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -48,7 +54,7 @@
public class OverviewCommandHelper {
public static final int TYPE_SHOW = 1;
- public static final int TYPE_SHOW_NEXT_FOCUS = 2;
+ public static final int TYPE_KEYBOARD_INPUT = 2;
public static final int TYPE_HIDE = 3;
public static final int TYPE_TOGGLE = 4;
public static final int TYPE_HOME = 5;
@@ -66,6 +72,13 @@
private final TaskAnimationManager mTaskAnimationManager;
private final ArrayList<CommandInfo> mPendingCommands = new ArrayList<>();
+ /**
+ * Index of the TaskView that should be focused when launching Overview. Persisted so that we
+ * do not lose the focus across multiple calls of
+ * {@link OverviewCommandHelper#executeCommand(CommandInfo)} for the same command
+ */
+ private int mTaskFocusIndexOverride = -1;
+
public OverviewCommandHelper(TouchInteractionService service,
OverviewComponentObserver observer,
TaskAnimationManager taskAnimationManager) {
@@ -165,8 +178,30 @@
mOverviewComponentObserver.getActivityInterface();
RecentsView recents = activityInterface.getVisibleRecentsView();
if (recents == null) {
+ T activity = activityInterface.getCreatedActivity();
+ DeviceProfile dp = activity == null ? null : activity.getDeviceProfile();
+ TaskbarUIController uiController = activityInterface.getTaskbarController();
+ boolean allowQuickSwitch = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+ && uiController != null
+ && dp != null
+ && (dp.isTablet || dp.isTwoPanels);
+
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ // TODO(b/268075592): add support for quickswitch to/from desktop
+ allowQuickSwitch = false;
+ }
+
if (cmd.type == TYPE_HIDE) {
- // already hidden
+ if (!allowQuickSwitch) {
+ return true;
+ }
+ mTaskFocusIndexOverride = uiController.launchFocusedTask();
+ if (mTaskFocusIndexOverride == -1) {
+ return true;
+ }
+ }
+ if (cmd.type == TYPE_KEYBOARD_INPUT && allowQuickSwitch) {
+ uiController.openQuickSwitchView();
return true;
}
if (cmd.type == TYPE_HOME) {
@@ -179,6 +214,7 @@
// already visible
return true;
case TYPE_HIDE: {
+ mTaskFocusIndexOverride = -1;
int currentPage = recents.getNextPage();
TaskView tv = (currentPage >= 0 && currentPage < recents.getTaskViewCount())
? (TaskView) recents.getPageAt(currentPage)
@@ -194,15 +230,9 @@
}
final Runnable completeCallback = () -> {
- if (cmd.type == TYPE_SHOW_NEXT_FOCUS) {
- RecentsView rv = activityInterface.getVisibleRecentsView();
- // When the overview is launched via alt tab (cmd type is TYPE_SHOW_NEXT_FOCUS),
- // the touch mode somehow is not change to false by the Android framework.
- // The subsequent tab to go through tasks in overview can only be dispatched to
- // focuses views, while focus can only be requested in
- // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
- // here we launch overview from home.
- rv.getViewRootImpl().touchModeChanged(false);
+ RecentsView rv = activityInterface.getVisibleRecentsView();
+ if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
+ updateRecentsViewFocus(rv);
}
scheduleNextTask(cmd);
};
@@ -253,7 +283,7 @@
RecentsView<?, ?> visibleRecentsView = activityInterface.getVisibleRecentsView();
if (visibleRecentsView != null) {
- visibleRecentsView.moveFocusedTaskToFront();
+ visibleRecentsView.moveRunningTaskToFront();
}
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
cmd.mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(gestureState);
@@ -280,40 +310,55 @@
cmd.removeListener(handler);
Trace.endAsyncSection(TRANSITION_NAME, 0);
- if (cmd.type == TYPE_SHOW_NEXT_FOCUS) {
- RecentsView rv =
- mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
- if (rv != null) {
- // When the overview is launched via alt tab (cmd type is TYPE_SHOW_NEXT_FOCUS),
- // the touch mode somehow is not change to false by the Android framework.
- // The subsequent tab to go through tasks in overview can only be dispatched to
- // focuses views, while focus can only be requested in
- // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
- // here we launch overview with live tile.
- rv.getViewRootImpl().touchModeChanged(false);
- // Ensure that recents view has focus so that it receives the followup key inputs
- TaskView taskView = rv.getNextTaskView();
- if (taskView == null) {
- taskView = rv.getTaskViewAt(0);
- if (taskView != null) {
- taskView.requestFocus();
- } else {
- rv.requestFocus();
- }
- } else {
- taskView.requestFocus();
- }
- }
+ RecentsView rv =
+ mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
+ if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
+ updateRecentsViewFocus(rv);
}
scheduleNextTask(cmd);
}
+ private void updateRecentsViewFocus(@NonNull RecentsView rv) {
+ // When the overview is launched via alt tab (cmd type is TYPE_KEYBOARD_INPUT),
+ // the touch mode somehow is not change to false by the Android framework.
+ // The subsequent tab to go through tasks in overview can only be dispatched to
+ // focuses views, while focus can only be requested in
+ // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
+ // here we launch overview with live tile.
+ rv.getViewRootImpl().touchModeChanged(false);
+ // Ensure that recents view has focus so that it receives the followup key inputs
+ TaskView taskView = rv.getTaskViewAt(mTaskFocusIndexOverride);
+ if (taskView != null) {
+ requestFocus(taskView);
+ return;
+ }
+ taskView = rv.getNextTaskView();
+ if (taskView != null) {
+ requestFocus(taskView);
+ return;
+ }
+ taskView = rv.getTaskViewAt(0);
+ if (taskView != null) {
+ requestFocus(taskView);
+ return;
+ }
+ requestFocus(rv);
+ }
+
+ private void requestFocus(@NonNull View view) {
+ view.post(() -> {
+ view.requestFocus();
+ view.requestAccessibilityFocus();
+ });
+ }
+
public void dump(PrintWriter pw) {
pw.println("OverviewCommandHelper:");
pw.println(" mPendingCommands=" + mPendingCommands.size());
if (!mPendingCommands.isEmpty()) {
pw.println(" pendingCommandType=" + mPendingCommands.get(0).type);
}
+ pw.println(" mTaskFocusIndexOverride=" + mTaskFocusIndexOverride);
}
private static class CommandInfo {
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 54e4a0d..5391f4d 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -59,7 +59,7 @@
}
Rect focusedTaskRect = new Rect();
LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
- focusedTaskRect);
+ focusedTaskRect, PagedOrientationHandler.PORTRAIT);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
return response;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index f26189c..3f8da56 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -134,7 +134,8 @@
SplitSelectStateController controller =
new SplitSelectStateController(this, mHandler, getStateManager(),
- /* depthController */ null, getStatsLogManager());
+ null /* depthController */, getStatsLogManager(),
+ SystemUiProxy.INSTANCE.get(this), RecentsModel.INSTANCE.get(this));
mDragLayer.recreateControllers();
mFallbackRecentsView.init(mActionsView, controller);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 1f522c1..9a23557 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -17,6 +17,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
@@ -51,8 +52,10 @@
import android.graphics.Region;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.os.UserManager;
import android.provider.Settings;
import android.view.MotionEvent;
@@ -62,9 +65,9 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -108,6 +111,15 @@
private final boolean mIsOneHandedModeSupported;
private boolean mPipIsActive;
+ private boolean mIsUserUnlocked;
+ private final ArrayList<Runnable> mUserUnlockedActions = new ArrayList<>();
+ private final SimpleBroadcastReceiver mUserUnlockedReceiver = new SimpleBroadcastReceiver(i -> {
+ if (ACTION_USER_UNLOCKED.equals(i.getAction())) {
+ mIsUserUnlocked = true;
+ notifyUserUnlocked();
+ }
+ });
+
private int mGestureBlockingTaskId = -1;
private @NonNull Region mExclusionRegion = new Region();
private SystemGestureExclusionListenerCompat mExclusionListener;
@@ -133,6 +145,14 @@
runOnDestroy(mRotationTouchHelper::destroy);
}
+ // Register for user unlocked if necessary
+ mIsUserUnlocked = context.getSystemService(UserManager.class)
+ .isUserUnlocked(Process.myUserHandle());
+ if (!mIsUserUnlocked) {
+ mUserUnlockedReceiver.register(mContext, ACTION_USER_UNLOCKED);
+ }
+ runOnDestroy(() -> mUserUnlockedReceiver.unregisterReceiverSafely(mContext));
+
// Register for exclusion updates
mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) {
@Override
@@ -292,12 +312,39 @@
}
/**
+ * Adds a callback for when a user is unlocked. If the user is already unlocked, this listener
+ * will be called back immediately.
+ */
+ public void runOnUserUnlocked(Runnable action) {
+ if (mIsUserUnlocked) {
+ action.run();
+ } else {
+ mUserUnlockedActions.add(action);
+ }
+ }
+
+ /**
+ * @return whether the user is unlocked.
+ */
+ public boolean isUserUnlocked() {
+ return mIsUserUnlocked;
+ }
+
+ /**
* @return whether the user has completed setup wizard
*/
public boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
+ private void notifyUserUnlocked() {
+ for (Runnable action : mUserUnlockedActions) {
+ action.run();
+ }
+ mUserUnlockedActions.clear();
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext);
+ }
+
/**
* Sets the task id where gestures should be blocked
*/
@@ -542,7 +589,7 @@
pw.println(" assistantAvailable=" + mAssistantAvailable);
pw.println(" assistantDisabled="
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
- pw.println(" isUserUnlocked=" + LockedUserState.get(mContext).isUserUnlocked());
+ pw.println(" isUserUnlocked=" + mIsUserUnlocked);
pw.println(" isOneHandedModeEnabled=" + mIsOneHandedModeEnabled);
pw.println(" isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled);
pw.println(" deferredGestureRegion=" + mDeferredGestureRegion.getBounds());
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 2200b35..86b02aa 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -57,6 +57,8 @@
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
+import com.android.systemui.unfold.progress.IUnfoldAnimation;
+import com.android.systemui.unfold.progress.IUnfoldTransitionListener;
import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.desktopmode.IDesktopMode;
import com.android.wm.shell.onehanded.IOneHanded;
@@ -96,6 +98,7 @@
private IRecentTasks mRecentTasks;
private IBackAnimation mBackAnimation;
private IDesktopMode mDesktopMode;
+ private IUnfoldAnimation mUnfoldAnimation;
private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
MAIN_EXECUTOR.execute(() -> clearProxy());
};
@@ -109,6 +112,7 @@
private IStartingWindowListener mStartingWindowListener;
private ILauncherUnlockAnimationController mLauncherUnlockAnimationController;
private IRecentTasksListener mRecentTasksListener;
+ private IUnfoldTransitionListener mUnfoldAnimationListener;
private final LinkedHashMap<RemoteTransition, TransitionFilter> mRemoteTransitions =
new LinkedHashMap<>();
private IOnBackInvokedCallback mBackToLauncherCallback;
@@ -171,7 +175,8 @@
IOneHanded oneHanded, IShellTransitions shellTransitions,
IStartingWindow startingWindow, IRecentTasks recentTasks,
ISysuiUnlockAnimationController sysuiUnlockAnimationController,
- IBackAnimation backAnimation, IDesktopMode desktopMode) {
+ IBackAnimation backAnimation, IDesktopMode desktopMode,
+ IUnfoldAnimation unfoldAnimation) {
unlinkToDeath();
mSystemUiProxy = proxy;
mPip = pip;
@@ -183,6 +188,7 @@
mRecentTasks = recentTasks;
mBackAnimation = backAnimation;
mDesktopMode = desktopMode;
+ mUnfoldAnimation = unfoldAnimation;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
if (mPipAnimationListener != null && mPip != null) {
@@ -204,10 +210,13 @@
if (mBackAnimation != null && mBackToLauncherCallback != null) {
setBackToLauncherCallback(mBackToLauncherCallback);
}
+ if (unfoldAnimation != null && mUnfoldAnimationListener != null) {
+ setUnfoldAnimationListener(mUnfoldAnimationListener);
+ }
}
public void clearProxy() {
- setProxy(null, null, null, null, null, null, null, null, null, null);
+ setProxy(null, null, null, null, null, null, null, null, null, null, null);
}
// TODO(141886704): Find a way to remove this
@@ -628,14 +637,20 @@
}
}
- public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, Bundle options1,
- PendingIntent pendingIntent2, Bundle options2,
- @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio,
- RemoteAnimationAdapter adapter, InstanceId instanceId) {
+ /**
+ * Starts a pair of intents or shortcuts in split-screen using legacy transition. Passing a
+ * non-null shortcut info means to start the app as a shortcut.
+ */
+ public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1,
+ @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1,
+ PendingIntent pendingIntent2, @Nullable ShortcutInfo shortcutInfo2,
+ @Nullable Bundle options2, @SplitConfigurationOptions.StagePosition int sidePosition,
+ float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
if (mSystemUiProxy != null) {
try {
- mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, options1,
- pendingIntent2, options2, sidePosition, splitRatio, adapter, instanceId);
+ mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, shortcutInfo1,
+ options1, pendingIntent2, shortcutInfo2, options2, sidePosition, splitRatio,
+ adapter, instanceId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntentsWithLegacyTransition");
}
@@ -961,4 +976,22 @@
}
return 0;
}
+
+ //
+ // Unfold transition
+ //
+
+ /** Sets the unfold animation lister to sysui. */
+ public void setUnfoldAnimationListener(IUnfoldTransitionListener callback) {
+ mUnfoldAnimationListener = callback;
+ if (mUnfoldAnimation == null) {
+ return;
+ }
+ try {
+ Log.d(TAG, "Registering unfold animation receiver");
+ mUnfoldAnimation.setListener(callback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed call setUnfoldAnimationListener", e);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index c45b2f0..725f9e7 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -40,6 +40,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.ActiveGestureLog;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -238,6 +239,12 @@
// to let the transition controller collect Home activity.
CachedTaskInfo cti = gestureState.getRunningTask();
boolean homeIsOnTop = cti != null && cti.isHomeTask();
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ if (cti != null && cti.isFreeformTask()) {
+ // No transient launch when desktop task is on top
+ homeIsOnTop = true;
+ }
+ }
if (!homeIsOnTop) {
options.setTransientLaunch();
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 0dcd723..6e47ff4 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -80,9 +80,10 @@
boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
boolean isTablet = activity.getDeviceProfile().isTablet;
- // Add overview actions to the menu when in in-place rotate landscape mode.
- if ((!canLauncherRotate && isInLandscape)
- || (isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get())) {
+ boolean isGridOnlyOverview = isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get();
+ // Add overview actions to the menu when in in-place rotate landscape mode, or in
+ // grid-only overview.
+ if ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview) {
// Add screenshot action to task menu.
List<SystemShortcut> screenshotShortcuts = TaskShortcutFactory.SCREENSHOT
.getShortcuts(activity, taskContainer);
@@ -90,8 +91,9 @@
shortcuts.addAll(screenshotShortcuts);
}
- // Add modal action only if display orientation is the same as the device orientation.
- if (orientedState.getDisplayRotation() == ROTATION_0) {
+ // Add modal action only if display orientation is the same as the device orientation,
+ // or in grid-only overview.
+ if (orientedState.getDisplayRotation() == ROTATION_0 || isGridOnlyOverview) {
List<SystemShortcut> modalShortcuts = TaskShortcutFactory.MODAL
.getShortcuts(activity, taskContainer);
if (modalShortcuts != null) {
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index e58845a..255b910 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -18,7 +18,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SELECTIONS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
import android.app.Activity;
@@ -393,10 +392,7 @@
taskContainer.getThumbnailView().getTaskOverlay()
.getModalStateSystemShortcut(
taskContainer.getItemInfo(), taskContainer.getTaskView());
- if (ENABLE_OVERVIEW_SELECTIONS.get()) {
- return createSingletonShortcutList(modalStateSystemShortcut);
- }
- return null;
+ return createSingletonShortcutList(modalStateSystemShortcut);
}
};
}
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index d4bf5c7..6d8ee10 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -18,6 +18,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.Intent.ACTION_CHOOSER;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -255,6 +256,15 @@
}
/**
+ * Returns {@code true} if this task windowing mode is set to {@link
+ * android.app.WindowConfiguration#WINDOWING_MODE_FREEFORM}
+ */
+ public boolean isFreeformTask() {
+ return mTopTask != null && mTopTask.configuration.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_FREEFORM;
+ }
+
+ /**
* Returns {@link Task} array which can be used as a placeholder until the true object
* is loaded by the model
*/
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 687ed36..accab38 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -28,6 +28,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
@@ -85,9 +86,9 @@
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.tracing.LauncherTraceProto;
import com.android.launcher3.tracing.TouchInteractionServiceProto;
+import com.android.launcher3.uioverrides.flags.FlagsFactory;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
@@ -114,6 +115,7 @@
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
import com.android.systemui.shared.tracing.ProtoTraceable;
+import com.android.systemui.unfold.progress.IUnfoldAnimation;
import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.desktopmode.IDesktopMode;
import com.android.wm.shell.onehanded.IOneHanded;
@@ -174,10 +176,13 @@
bundle.getBinder(KEY_EXTRA_SHELL_BACK_ANIMATION));
IDesktopMode desktopMode = IDesktopMode.Stub.asInterface(
bundle.getBinder(KEY_EXTRA_SHELL_DESKTOP_MODE));
+ IUnfoldAnimation unfoldTransition = IUnfoldAnimation.Stub.asInterface(
+ bundle.getBinder(KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER));
MAIN_EXECUTOR.execute(() -> {
SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
splitscreen, onehanded, shellTransitions, startingWindow,
- recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode);
+ recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
+ unfoldTransition);
TouchInteractionService.this.initInputMonitor("TISBinder#onInitialize()");
preloadOverview(true /* fromInit */);
});
@@ -200,7 +205,7 @@
public void onOverviewShown(boolean triggeredFromAltTab) {
if (triggeredFromAltTab) {
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
- mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW_NEXT_FOCUS);
+ mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_KEYBOARD_INPUT);
} else {
mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
}
@@ -405,10 +410,11 @@
mDeviceState = new RecentsAnimationDeviceState(this, true);
mTaskbarManager = new TaskbarManager(this);
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
+ BootAwarePreloader.start(this);
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
- LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
- LockedUserState.get(this).runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
+ mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
+ mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
ProtoTracer.INSTANCE.get(this).add(this);
@@ -478,7 +484,7 @@
}
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
- if (!LockedUserState.get(this).isUserUnlocked() || mDeviceState.isButtonNavMode()) {
+ if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
// Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
// mode doesn't have gestures
return;
@@ -521,7 +527,7 @@
@UiThread
private void onSystemUiFlagsChanged(int lastSysUIFlags) {
- if (LockedUserState.get(this).isUserUnlocked()) {
+ if (mDeviceState.isUserUnlocked()) {
int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
mOverviewComponentObserver.onSystemUiStateChanged();
@@ -566,7 +572,7 @@
@UiThread
private void onAssistantVisibilityChanged() {
- if (LockedUserState.get(this).isUserUnlocked()) {
+ if (mDeviceState.isUserUnlocked()) {
mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
mDeviceState.getAssistantVisibility());
}
@@ -576,7 +582,7 @@
public void onDestroy() {
Log.d(TAG, "Touch service destroyed: user=" + getUserId());
sIsInitialized = false;
- if (LockedUserState.get(this).isUserUnlocked()) {
+ if (mDeviceState.isUserUnlocked()) {
mInputConsumer.unregisterInputConsumer();
mOverviewComponentObserver.onDestroy();
}
@@ -610,7 +616,7 @@
TestLogging.recordMotionEvent(
TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
return;
}
@@ -632,8 +638,7 @@
mGestureState = newGestureState;
mConsumer = newConsumer(prevGestureState, mGestureState, event);
mUncheckedConsumer = mConsumer;
- } else if (LockedUserState.get(this).isUserUnlocked()
- && mDeviceState.isFullyGesturalNavMode()
+ } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()
&& mDeviceState.canTriggerAssistantAction(event)) {
mGestureState = createGestureState(mGestureState);
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
@@ -753,7 +758,7 @@
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
CompoundString reasonString = newCompoundString("device locked");
InputConsumer consumer;
if (canStartSystemGesture) {
@@ -1100,7 +1105,7 @@
}
private void preloadOverview(boolean fromInit, boolean forSUWAllSet) {
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
return;
}
@@ -1132,7 +1137,7 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
return;
}
final BaseActivityInterface activityInterface =
@@ -1172,8 +1177,8 @@
}
} else {
// Dump everything
- FeatureFlags.dump(pw);
- if (LockedUserState.get(this).isUserUnlocked()) {
+ FlagsFactory.dump(pw);
+ if (mDeviceState.isUserUnlocked()) {
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
}
mDeviceState.dump(pw);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 062e50e..11b1ab8 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -130,15 +130,9 @@
mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset(
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
mActivity.getDeviceProfile());
+ setter.setFloat(mRecentsView, taskViewsFloat.first, isSplitSelectionState(state)
+ ? mRecentsView.getSplitSelectTranslation() : 0, LINEAR);
setter.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
- if (isSplitSelectionState(state)) {
- mRecentsView.applySplitPrimaryScrollOffset();
- setter.setFloat(mRecentsView, taskViewsFloat.first,
- mRecentsView.getSplitSelectTranslation(), LINEAR);
- } else {
- mRecentsView.resetSplitPrimaryScrollOffset();
- setter.setFloat(mRecentsView, taskViewsFloat.first, 0, LINEAR);
- }
}
/**
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index db6d56b..4b1dd43 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep.fallback;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.HOME;
@@ -200,8 +202,9 @@
}
@Override
- public void setModalStateEnabled(boolean isModalState, boolean animate) {
- if (isModalState) {
+ public void setModalStateEnabled(int taskId, boolean animate) {
+ if (taskId != INVALID_TASK_ID) {
+ setSelectedTask(taskId);
mActivity.getStateManager().goToState(RecentsState.MODAL_TASK, animate);
} else {
if (mActivity.isInState(RecentsState.MODAL_TASK)) {
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
index 53ad138..3ccd683 100644
--- a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
@@ -30,7 +30,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.cardview.widget.CardView;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
@@ -46,8 +45,8 @@
public class AnimatedTaskView extends ConstraintLayout {
private View mFullTaskView;
- private CardView mTopTaskView;
- private CardView mBottomTaskView;
+ private View mTopTaskView;
+ private View mBottomTaskView;
private ViewOutlineProvider mTaskViewOutlineProvider = null;
private final Rect mTaskViewAnimatedRect = new Rect();
@@ -185,8 +184,6 @@
void setFakeTaskViewFillColor(@ColorInt int colorResId) {
mFullTaskView.setBackgroundColor(colorResId);
- mTopTaskView.setCardBackgroundColor(colorResId);
- mBottomTaskView.setCardBackgroundColor(colorResId);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index c89d4b6..bce639b 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -61,10 +61,10 @@
@Override
protected int getMockAppTaskLayoutResId() {
- return mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_tablet_mock_webpage
- : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.swipe_up_gesture_tutorial_shape
+ return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
+ ? R.layout.swipe_up_gesture_tutorial_shape
+ : mTutorialFragment.isLargeScreen()
+ ? R.layout.gesture_tutorial_tablet_mock_webpage
: R.layout.gesture_tutorial_mock_webpage;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
index ac0c17d..bd0ce34 100644
--- a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
+++ b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
@@ -15,17 +15,30 @@
*/
package com.android.quickstep.interaction;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
+
import android.content.Context;
import android.graphics.Insets;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.View;
import android.view.WindowInsets;
import android.widget.RelativeLayout;
+import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
/** Root layout that TutorialFragment uses to intercept motion events. */
public class RootSandboxLayout extends RelativeLayout {
+
+ private View mFeedbackView;
+ private View mTutorialStepView;
+ private View mSkipButton;
+ private View mDoneButton;
+
public RootSandboxLayout(Context context) {
super(context);
}
@@ -52,4 +65,51 @@
return getHeight() + insets.top + insets.bottom;
}
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
+ return;
+ }
+ mFeedbackView = findViewById(R.id.gesture_tutorial_fragment_feedback_view);
+ mTutorialStepView =
+ mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_tutorial_step);
+ mSkipButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_close_button);
+ mDoneButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_action_button);
+
+ mFeedbackView.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ if (mSkipButton.getVisibility() != VISIBLE
+ && mDoneButton.getVisibility() != VISIBLE) {
+ return;
+ }
+ // Either the skip or the done button is ever shown at once, never both.
+ boolean showingSkipButton = mSkipButton.getVisibility() == VISIBLE;
+ boolean isRTL = Utilities.isRtl(getContext().getResources());
+ updateTutorialStepViewTranslation(
+ showingSkipButton ? mSkipButton : mDoneButton,
+ // Translate the step indicator away from whichever button is being
+ // shown. The skip button in on the left in LTR or on the right in RTL.
+ // The done button is on the right in LTR or left in RTL.
+ (showingSkipButton && !isRTL) || (!showingSkipButton && isRTL));
+ });
+ }
+
+ private void updateTutorialStepViewTranslation(
+ @NonNull View anchorView, boolean translateToRight) {
+ mTutorialStepView.setTranslationX(translateToRight
+ ? Math.min(
+ // Translate to the right if the views are overlapping on large fonts and
+ // display sizes.
+ Math.max(0, anchorView.getRight() - mTutorialStepView.getLeft()),
+ // Do not translate beyond the bounds of the container view.
+ mFeedbackView.getWidth() - mTutorialStepView.getRight())
+ : Math.max(
+ // Translate to the left if the views are overlapping on large fonts and
+ // display sizes.
+ Math.min(0, anchorView.getLeft() - mTutorialStepView.getRight()),
+ // Do not translate beyond the bounds of the container view.
+ -mTutorialStepView.getLeft()));
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index ccdb266..6fcb840 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -154,7 +154,6 @@
mFeedbackTitleView.setText(getIntroductionTitle());
mFeedbackSubtitleView.setText(getIntroductionSubtitle());
- mSkipButton.setVisibility(GONE);
}
mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index 60065fb..2964868 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -20,7 +20,6 @@
import androidx.annotation.NonNull;
import java.io.PrintWriter;
-import java.util.List;
import java.util.Set;
/**
@@ -37,7 +36,7 @@
ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION,
CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION,
CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
- FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER,
+ FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED,
/**
* These GestureEvents are specifically associated to state flags that get set in
@@ -68,288 +67,288 @@
protected static void analyseAndDump(
@NonNull String prefix,
@NonNull PrintWriter writer,
- List<ActiveGestureLog.EventLog> eventLogs) {
- writer.println(prefix + "ActiveGestureErrorDetector:");
- for (int i = 0; i < eventLogs.size(); i++) {
- ActiveGestureLog.EventLog eventLog = eventLogs.get(i);
- if (eventLog == null) {
+ @NonNull ActiveGestureLog.EventLog eventLog) {
+ writer.println(prefix + "Error messages for gesture ID: " + eventLog.logId);
+
+ boolean errorDetected = false;
+ // Use a Set since the order is inherently checked in the loop.
+ final Set<GestureEvent> encounteredEvents = new ArraySet<>();
+ // Set flags and check order of operations.
+ for (ActiveGestureLog.EventEntry eventEntry : eventLog.eventEntries) {
+ GestureEvent gestureEvent = eventEntry.getGestureEvent();
+ if (gestureEvent == null) {
continue;
}
- int gestureId = eventLog.logId;
- writer.println(prefix + "\tError messages for gesture ID: " + gestureId);
+ encounteredEvents.add(gestureEvent);
- boolean errorDetected = false;
- // Use a Set since the order is inherently checked in the loop.
- final Set<GestureEvent> encounteredEvents = new ArraySet<>();
- // Set flags and check order of operations.
- for (ActiveGestureLog.EventEntry eventEntry : eventLog.eventEntries) {
- GestureEvent gestureEvent = eventEntry.getGestureEvent();
- if (gestureEvent == null) {
- continue;
- }
- encounteredEvents.add(gestureEvent);
- switch (gestureEvent) {
- case MOTION_UP:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
- prefix,
- /* errorMessage= */ "Motion up detected before/without"
- + " motion down.",
- writer);
- break;
- case ON_SETTLED_ON_END_TARGET:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET),
- prefix,
- /* errorMessage= */ "onSettledOnEndTarget called "
- + "before/without setEndTarget.",
- writer);
- break;
- case FINISH_RECENTS_ANIMATION:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "finishRecentsAnimation called "
- + "before/without startRecentsAnimation.",
- writer);
- break;
- case CANCEL_RECENTS_ANIMATION:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "cancelRecentsAnimation called "
- + "before/without startRecentsAnimation.",
- writer);
- break;
- case CLEANUP_SCREENSHOT:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
- prefix,
- /* errorMessage= */ "recents activity screenshot was "
- + "cleaned up before/without STATE_SCREENSHOT_CAPTURED "
- + "being set.",
- writer);
- break;
- case SCROLLER_ANIMATION_ABORTED:
- errorDetected |= printErrorIfTrue(
- encounteredEvents.contains(GestureEvent.SET_END_TARGET_HOME)
- && !encounteredEvents.contains(
- GestureEvent.ON_SETTLED_ON_END_TARGET),
- prefix,
- /* errorMessage= */ "recents view scroller animation "
- + "aborted after setting end target HOME, but before"
- + " settling on end target.",
- writer);
- break;
- case TASK_APPEARED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
- prefix,
- /* errorMessage= */ "onTasksAppeared called "
- + "before/without setting end target to new task",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED),
- prefix,
- /* errorMessage= */ "onTasksAppeared was not expected to be called",
- writer);
- break;
- case EXPECTING_TASK_APPEARED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
- prefix,
- /* errorMessage= */ "expecting onTasksAppeared to be called "
- + "before/without setting end target to new task",
- writer);
- break;
- case STATE_GESTURE_COMPLETED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_UP),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
- + "before/without motion up.",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
- + "before/without STATE_GESTURE_STARTED.",
- writer);
- break;
- case STATE_GESTURE_CANCELLED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_UP),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
- + "before/without motion up.",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
- + "before/without STATE_GESTURE_STARTED.",
- writer);
- break;
- case STATE_SCREENSHOT_CAPTURED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_CAPTURE_SCREENSHOT),
- prefix,
- /* errorMessage= */ "STATE_SCREENSHOT_CAPTURED set "
- + "before/without STATE_CAPTURE_SCREENSHOT.",
- writer);
- break;
- case STATE_RECENTS_SCROLLING_FINISHED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(
- GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK),
- prefix,
- /* errorMessage= */ "STATE_RECENTS_SCROLLING_FINISHED "
- + "set before/without calling "
- + "setOnPageTransitionEndCallback.",
- writer);
- break;
- case STATE_RECENTS_ANIMATION_CANCELED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(
- GestureEvent.START_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED "
- + "set before/without startRecentsAnimation.",
- writer);
- break;
- case MOTION_DOWN:
- case SET_END_TARGET:
- case SET_END_TARGET_HOME:
- case SET_END_TARGET_NEW_TASK:
- case START_RECENTS_ANIMATION:
- case SET_ON_PAGE_TRANSITION_END_CALLBACK:
- case CANCEL_CURRENT_ANIMATION:
- case FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER:
- case STATE_GESTURE_STARTED:
- case STATE_END_TARGET_ANIMATION_FINISHED:
- case STATE_CAPTURE_SCREENSHOT:
- case STATE_HANDLER_INVALIDATED:
- case STATE_LAUNCHER_DRAWN:
- default:
- // No-Op
- }
+ switch (gestureEvent) {
+ case MOTION_UP:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
+ prefix,
+ /* errorMessage= */ "Motion up detected before/without"
+ + " motion down.",
+ writer);
+ break;
+ case ON_SETTLED_ON_END_TARGET:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.SET_END_TARGET),
+ prefix,
+ /* errorMessage= */ "onSettledOnEndTarget called "
+ + "before/without setEndTarget.",
+ writer);
+ break;
+ case FINISH_RECENTS_ANIMATION:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "finishRecentsAnimation called "
+ + "before/without startRecentsAnimation.",
+ writer);
+ break;
+ case CANCEL_RECENTS_ANIMATION:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "cancelRecentsAnimation called "
+ + "before/without startRecentsAnimation.",
+ writer);
+ break;
+ case CLEANUP_SCREENSHOT:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
+ prefix,
+ /* errorMessage= */ "recents activity screenshot was "
+ + "cleaned up before/without STATE_SCREENSHOT_CAPTURED "
+ + "being set.",
+ writer);
+ break;
+ case SCROLLER_ANIMATION_ABORTED:
+ errorDetected |= printErrorIfTrue(
+ encounteredEvents.contains(GestureEvent.SET_END_TARGET_HOME)
+ && !encounteredEvents.contains(
+ GestureEvent.ON_SETTLED_ON_END_TARGET),
+ prefix,
+ /* errorMessage= */ "recents view scroller animation "
+ + "aborted after setting end target HOME, but before"
+ + " settling on end target.",
+ writer);
+ break;
+ case TASK_APPEARED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
+ prefix,
+ /* errorMessage= */ "onTasksAppeared called "
+ + "before/without setting end target to new task",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED),
+ prefix,
+ /* errorMessage= */ "onTasksAppeared was not expected to be called",
+ writer);
+ break;
+ case EXPECTING_TASK_APPEARED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
+ prefix,
+ /* errorMessage= */ "expecting onTasksAppeared to be called "
+ + "before/without setting end target to new task",
+ writer);
+ break;
+ case LAUNCHER_DESTROYED:
+ errorDetected |= printErrorIfTrue(
+ true,
+ prefix,
+ /* errorMessage= */ "Launcher destroyed mid-gesture",
+ writer);
+ break;
+ case STATE_GESTURE_COMPLETED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_UP),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
+ + "before/without motion up.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
+ + "before/without STATE_GESTURE_STARTED.",
+ writer);
+ break;
+ case STATE_GESTURE_CANCELLED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_UP),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
+ + "before/without motion up.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
+ + "before/without STATE_GESTURE_STARTED.",
+ writer);
+ break;
+ case STATE_SCREENSHOT_CAPTURED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_CAPTURE_SCREENSHOT),
+ prefix,
+ /* errorMessage= */ "STATE_SCREENSHOT_CAPTURED set "
+ + "before/without STATE_CAPTURE_SCREENSHOT.",
+ writer);
+ break;
+ case STATE_RECENTS_SCROLLING_FINISHED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(
+ GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK),
+ prefix,
+ /* errorMessage= */ "STATE_RECENTS_SCROLLING_FINISHED "
+ + "set before/without calling "
+ + "setOnPageTransitionEndCallback.",
+ writer);
+ break;
+ case STATE_RECENTS_ANIMATION_CANCELED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(
+ GestureEvent.START_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED "
+ + "set before/without startRecentsAnimation.",
+ writer);
+ break;
+ case MOTION_DOWN:
+ case SET_END_TARGET:
+ case SET_END_TARGET_HOME:
+ case SET_END_TARGET_NEW_TASK:
+ case START_RECENTS_ANIMATION:
+ case SET_ON_PAGE_TRANSITION_END_CALLBACK:
+ case CANCEL_CURRENT_ANIMATION:
+ case FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER:
+ case STATE_GESTURE_STARTED:
+ case STATE_END_TARGET_ANIMATION_FINISHED:
+ case STATE_CAPTURE_SCREENSHOT:
+ case STATE_HANDLER_INVALIDATED:
+ case STATE_LAUNCHER_DRAWN:
+ default:
+ // No-Op
}
+ }
- // Check that all required events were found.
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
- prefix,
- /* errorMessage= */ "Motion down never detected.",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_UP),
- prefix,
- /* errorMessage= */ "Motion up never detected.",
- writer);
+ // Check that all required events were found.
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
+ prefix,
+ /* errorMessage= */ "Motion down never detected.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_UP),
+ prefix,
+ /* errorMessage= */ "Motion up never detected.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
- && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
- prefix,
- /* errorMessage= */ "setEndTarget was called, but "
- + "onSettledOnEndTarget wasn't.",
- writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
- && !encounteredEvents.contains(
- GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED),
- prefix,
- /* errorMessage= */ "setEndTarget was called, but "
- + "STATE_END_TARGET_ANIMATION_FINISHED was never set.",
- writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
- && !encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
- prefix,
- /* errorMessage= */ "setEndTarget was called, but "
- + "STATE_RECENTS_SCROLLING_FINISHED was never set.",
- writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED)
- && encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_SCROLLING_FINISHED)
- && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
- prefix,
- /* errorMessage= */ "STATE_END_TARGET_ANIMATION_FINISHED and "
- + "STATE_RECENTS_SCROLLING_FINISHED were set, but onSettledOnEndTarget "
- + "wasn't called.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
+ && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
+ prefix,
+ /* errorMessage= */ "setEndTarget was called, but "
+ + "onSettledOnEndTarget wasn't.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
+ && !encounteredEvents.contains(
+ GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED),
+ prefix,
+ /* errorMessage= */ "setEndTarget was called, but "
+ + "STATE_END_TARGET_ANIMATION_FINISHED was never set.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
+ && !encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
+ prefix,
+ /* errorMessage= */ "setEndTarget was called, but "
+ + "STATE_RECENTS_SCROLLING_FINISHED was never set.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED)
+ && encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_SCROLLING_FINISHED)
+ && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
+ prefix,
+ /* errorMessage= */ "STATE_END_TARGET_ANIMATION_FINISHED and "
+ + "STATE_RECENTS_SCROLLING_FINISHED were set, but onSettledOnEndTarget "
+ + "wasn't called.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.START_RECENTS_ANIMATION)
- && !encounteredEvents.contains(GestureEvent.FINISH_RECENTS_ANIMATION)
- && !encounteredEvents.contains(GestureEvent.CANCEL_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "startRecentsAnimation was called, but "
- + "finishRecentsAnimation and cancelRecentsAnimation weren't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.START_RECENTS_ANIMATION)
+ && !encounteredEvents.contains(GestureEvent.FINISH_RECENTS_ANIMATION)
+ && !encounteredEvents.contains(GestureEvent.CANCEL_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "startRecentsAnimation was called, but "
+ + "finishRecentsAnimation and cancelRecentsAnimation weren't.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED)
- && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_COMPLETED)
- && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_CANCELLED),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_STARTED was set, but "
- + "STATE_GESTURE_COMPLETED and STATE_GESTURE_CANCELLED weren't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED)
+ && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_COMPLETED)
+ && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_CANCELLED),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_STARTED was set, but "
+ + "STATE_GESTURE_COMPLETED and STATE_GESTURE_CANCELLED weren't.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.STATE_CAPTURE_SCREENSHOT)
- && !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
- prefix,
- /* errorMessage= */ "STATE_CAPTURE_SCREENSHOT was set, but "
- + "STATE_SCREENSHOT_CAPTURED wasn't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.STATE_CAPTURE_SCREENSHOT)
+ && !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
+ prefix,
+ /* errorMessage= */ "STATE_CAPTURE_SCREENSHOT was set, but "
+ + "STATE_SCREENSHOT_CAPTURED wasn't.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK)
- && !encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
- prefix,
- /* errorMessage= */ "setOnPageTransitionEndCallback called, but "
- + "STATE_RECENTS_SCROLLING_FINISHED wasn't set.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK)
+ && !encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
+ prefix,
+ /* errorMessage= */ "setOnPageTransitionEndCallback called, but "
+ + "STATE_RECENTS_SCROLLING_FINISHED wasn't set.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER)
- && !encounteredEvents.contains(GestureEvent.CANCEL_CURRENT_ANIMATION)
- && !encounteredEvents.contains(GestureEvent.STATE_HANDLER_INVALIDATED),
- prefix,
- /* errorMessage= */ "AbsSwipeUpHandler.cancelCurrentAnimation "
- + "wasn't called and STATE_HANDLER_INVALIDATED wasn't set.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER)
+ && !encounteredEvents.contains(GestureEvent.CANCEL_CURRENT_ANIMATION)
+ && !encounteredEvents.contains(GestureEvent.STATE_HANDLER_INVALIDATED),
+ prefix,
+ /* errorMessage= */ "AbsSwipeUpHandler.cancelCurrentAnimation "
+ + "wasn't called and STATE_HANDLER_INVALIDATED wasn't set.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_ANIMATION_CANCELED)
- && !encounteredEvents.contains(GestureEvent.CLEANUP_SCREENSHOT),
- prefix,
- /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED was set but "
- + "the task screenshot wasn't cleaned up.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_ANIMATION_CANCELED)
+ && !encounteredEvents.contains(GestureEvent.CLEANUP_SCREENSHOT),
+ prefix,
+ /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED was set but "
+ + "the task screenshot wasn't cleaned up.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.EXPECTING_TASK_APPEARED)
- && !encounteredEvents.contains(GestureEvent.TASK_APPEARED),
- prefix,
- /* errorMessage= */ "onTaskAppeared was expected to be called but wasn't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.EXPECTING_TASK_APPEARED)
+ && !encounteredEvents.contains(GestureEvent.TASK_APPEARED),
+ prefix,
+ /* errorMessage= */ "onTaskAppeared was expected to be called but wasn't.",
+ writer);
- if (!errorDetected) {
- writer.println(prefix + "\t\tNo errors detected.");
- }
+ if (!errorDetected) {
+ writer.println(prefix + "\tNo errors detected.");
}
}
@@ -358,7 +357,8 @@
if (!condition) {
return false;
}
- writer.println(prefix + "\t\t- " + errorMessage);
+ writer.println(prefix + "\t- " + errorMessage);
+
return true;
}
}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 23fdd58..e05d85c 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -155,19 +155,27 @@
}
public void dump(String prefix, PrintWriter writer) {
+ if (FeatureFlags.ENABLE_GESTURE_ERROR_DETECTION.get()) {
+ writer.println(prefix + "ActiveGestureErrorDetector:");
+ for (int i = 0; i < logs.length; i++) {
+ EventLog eventLog = logs[(nextIndex + i) % logs.length];
+ if (eventLog == null) {
+ continue;
+ }
+ ActiveGestureErrorDetector.analyseAndDump(prefix + '\t', writer, eventLog);
+ }
+ }
+
writer.println(prefix + "ActiveGestureLog history:");
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSZ ", Locale.US);
Date date = new Date();
- ArrayList<EventLog> eventLogs = new ArrayList<>();
-
for (int i = 0; i < logs.length; i++) {
EventLog eventLog = logs[(nextIndex + i) % logs.length];
if (eventLog == null) {
continue;
}
- eventLogs.add(eventLog);
- writer.println(prefix + "\tLogs for logId: " + eventLog.logId);
+ writer.println(prefix + "\tLogs for logId: " + eventLog.logId);
for (EventEntry eventEntry : eventLog.eventEntries) {
date.setTime(eventEntry.time);
@@ -199,10 +207,6 @@
writer.println(msg);
}
}
-
- if (FeatureFlags.ENABLE_GESTURE_ERROR_DETECTION.get()) {
- ActiveGestureErrorDetector.analyseAndDump(prefix + '\t', writer, eventLogs);
- }
}
/**
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index 7c83833..baca76c 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -158,7 +158,8 @@
Rect startRect = new Rect();
PagedOrientationHandler orientationHandler = params.recentsOrientedState
.getOrientationHandler();
- LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect);
+ LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect,
+ orientationHandler);
long distanceToCover = startRect.bottom;
PendingAnimation resistAnim = params.resistAnim != null
? params.resistAnim
diff --git a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
index 2a513ee..2a8bfa2 100644
--- a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
@@ -56,7 +56,6 @@
mAnimationInProgress = true;
mMoveFromCenterAnimation.updateDisplayProperties();
onPrepareViewsForAnimation();
- onTransitionProgress(0f);
mRotationChangeProvider.addCallback(mRotationListener);
}
@@ -101,22 +100,34 @@
mMoveFromCenterAnimation.registerViewForAnimation(view);
}
- protected void disableClipping(ViewGroup view) {
+ /**
+ * Sets clipToPadding for the view which then could be restored to the original value
+ * using {@link BaseUnfoldMoveFromCenterAnimator#restoreClippings} method call
+ * @param view view to set the property
+ * @param clipToPadding value of the property
+ */
+ protected void setClipToPadding(ViewGroup view, boolean clipToPadding) {
mOriginalClipToPadding.put(view, view.getClipToPadding());
- mOriginalClipChildren.put(view, view.getClipChildren());
- view.setClipToPadding(false);
- view.setClipChildren(false);
+ view.setClipToPadding(clipToPadding);
}
- protected void restoreClipping(ViewGroup view) {
- final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
- if (originalClipToPadding != null) {
- view.setClipToPadding(originalClipToPadding);
- }
- final Boolean originalClipChildren = mOriginalClipChildren.get(view);
- if (originalClipChildren != null) {
- view.setClipChildren(originalClipChildren);
- }
+ /**
+ * Sets clipChildren for the view which then could be restored to the original value
+ * using {@link BaseUnfoldMoveFromCenterAnimator#restoreClippings} method call
+ * @param view view to set the property
+ * @param clipChildren value of the property
+ */
+ protected void setClipChildren(ViewGroup view, boolean clipChildren) {
+ mOriginalClipChildren.put(view, view.getClipChildren());
+ view.setClipChildren(clipChildren);
+ }
+
+ /**
+ * Restores original clip properties after their modifications
+ */
+ protected void restoreClippings() {
+ mOriginalClipToPadding.forEach(ViewGroup::setClipToPadding);
+ mOriginalClipChildren.forEach(ViewGroup::setClipChildren);
}
private class UnfoldMoveFromCenterRotationListener implements
diff --git a/quickstep/src/com/android/quickstep/util/BorderAnimator.java b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
new file mode 100644
index 0000000..1f1c15b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
@@ -0,0 +1,177 @@
+/*
+ * 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.quickstep.util;
+
+import android.animation.Animator;
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.animation.Interpolator;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Px;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.anim.Interpolators;
+
+/**
+ * Utility class for drawing a rounded-rect border around a view.
+ * <p>
+ * To use this class:
+ * 1. Create an instance in the target view.
+ * 2. Override the target view's {@link android.view.View#draw(Canvas)} method and call
+ * {@link BorderAnimator#drawBorder(Canvas)} after {@code super.draw(canvas)}.
+ * 3. Call {@link BorderAnimator#buildAnimator(boolean)} and start the animation or call
+ * {@link BorderAnimator#setBorderVisible(boolean)} where appropriate.
+ */
+public final class BorderAnimator {
+
+ public static final int DEFAULT_BORDER_COLOR = 0xffffffff;
+
+ private static final long DEFAULT_APPEARANCE_ANIMATION_DURATION_MS = 300;
+ private static final long DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS = 133;
+ private static final Interpolator DEFAULT_INTERPOLATOR = Interpolators.EMPHASIZED_DECELERATE;
+
+ @NonNull private final AnimatedFloat mBorderAnimationProgress = new AnimatedFloat(
+ this::updateOutline);
+ @NonNull private final Rect mBorderBounds = new Rect();
+ @NonNull private final BorderBoundsBuilder mBorderBoundsBuilder;
+ @Px private final int mBorderWidthPx;
+ @Px private final int mBorderRadiusPx;
+ @NonNull private final Runnable mInvalidateViewCallback;
+ private final long mAppearanceDurationMs;
+ private final long mDisappearanceDurationMs;
+ @NonNull private final Interpolator mInterpolator;
+ @NonNull private final Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ private int mAlignmentAdjustment;
+
+ @Nullable private Animator mRunningBorderAnimation;
+
+ public BorderAnimator(
+ @NonNull BorderBoundsBuilder borderBoundsBuilder,
+ int borderWidthPx,
+ int borderRadiusPx,
+ @ColorInt int borderColor,
+ @NonNull Runnable invalidateViewCallback) {
+ this(borderBoundsBuilder,
+ borderWidthPx,
+ borderRadiusPx,
+ borderColor,
+ invalidateViewCallback,
+ DEFAULT_APPEARANCE_ANIMATION_DURATION_MS,
+ DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS,
+ DEFAULT_INTERPOLATOR);
+ }
+
+ public BorderAnimator(
+ @NonNull BorderBoundsBuilder borderBoundsBuilder,
+ int borderWidthPx,
+ int borderRadiusPx,
+ @ColorInt int borderColor,
+ @NonNull Runnable invalidateViewCallback,
+ long appearanceDurationMs,
+ long disappearanceDurationMs,
+ @NonNull Interpolator interpolator) {
+ mBorderBoundsBuilder = borderBoundsBuilder;
+ mBorderWidthPx = borderWidthPx;
+ mBorderRadiusPx = borderRadiusPx;
+ mInvalidateViewCallback = invalidateViewCallback;
+ mAppearanceDurationMs = appearanceDurationMs;
+ mDisappearanceDurationMs = disappearanceDurationMs;
+ mInterpolator = interpolator;
+
+ mBorderPaint.setColor(borderColor);
+ mBorderPaint.setStyle(Paint.Style.STROKE);
+ mBorderPaint.setAlpha(0);
+ }
+
+ private void updateOutline() {
+ float interpolatedProgress = mInterpolator.getInterpolation(
+ mBorderAnimationProgress.value);
+ mAlignmentAdjustment = (int) Utilities.mapBoundToRange(
+ mBorderAnimationProgress.value,
+ /* lowerBound= */ 0f,
+ /* upperBound= */ 1f,
+ /* toMin= */ 0f,
+ /* toMax= */ (float) (mBorderWidthPx / 2f),
+ mInterpolator);
+
+ mBorderPaint.setAlpha(Math.round(255 * interpolatedProgress));
+ mBorderPaint.setStrokeWidth(Math.round(mBorderWidthPx * interpolatedProgress));
+ mInvalidateViewCallback.run();
+ }
+
+ /**
+ * Draws the border on the given canvas.
+ * <p>
+ * Call this method in the target view's {@link android.view.View#draw(Canvas)} method after
+ * calling super.
+ */
+ public void drawBorder(Canvas canvas) {
+ canvas.drawRoundRect(
+ /* left= */ mBorderBounds.left + mAlignmentAdjustment,
+ /* top= */ mBorderBounds.top + mAlignmentAdjustment,
+ /* right= */ mBorderBounds.right - mAlignmentAdjustment,
+ /* bottom= */ mBorderBounds.bottom - mAlignmentAdjustment,
+ /* rx= */ mBorderRadiusPx - mAlignmentAdjustment,
+ /* ry= */ mBorderRadiusPx - mAlignmentAdjustment,
+ /* paint= */ mBorderPaint);
+ }
+
+ /**
+ * Builds the border appearance/disappearance animation.
+ */
+ @NonNull
+ public Animator buildAnimator(boolean isAppearing) {
+ mBorderBoundsBuilder.updateBorderBounds(mBorderBounds);
+ mRunningBorderAnimation = mBorderAnimationProgress.animateToValue(isAppearing ? 1f : 0f);
+ mRunningBorderAnimation.setDuration(
+ isAppearing ? mAppearanceDurationMs : mDisappearanceDurationMs);
+
+ mRunningBorderAnimation.addListener(
+ AnimatorListeners.forEndCallback(() -> mRunningBorderAnimation = null));
+
+ return mRunningBorderAnimation;
+ }
+
+ /**
+ * Immediately shows/hides the border without an animation.
+ *
+ * To animate the appearance/disappearance, see {@link BorderAnimator#buildAnimator(boolean)}
+ */
+ public void setBorderVisible(boolean visible) {
+ if (mRunningBorderAnimation != null) {
+ mRunningBorderAnimation.end();
+ }
+ mBorderAnimationProgress.updateValue(visible ? 1f : 0f);
+ }
+
+ /**
+ * Callback to update the border bounds when building this animation.
+ */
+ public interface BorderBoundsBuilder {
+
+ /**
+ * Sets the given rect to the most up-to-date bounds.
+ */
+ void updateBorderBounds(Rect rect);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index f7136a5..79656c2 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -43,7 +43,8 @@
PagedOrientationHandler orientationHandler) {
// Track the bottom of the window.
Rect taskSize = new Rect();
- LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize);
+ LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
+ orientationHandler);
return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
}
diff --git a/quickstep/src/com/android/quickstep/util/LogUtils.kt b/quickstep/src/com/android/quickstep/util/LogUtils.kt
index 300c4a1..23a41f6 100644
--- a/quickstep/src/com/android/quickstep/util/LogUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/LogUtils.kt
@@ -22,7 +22,7 @@
object LogUtils {
/**
* @return a [Pair] of two InstanceIds but with different types, one that can be used by
- * framework (if needing to pass through an intent or such) and one used in Launcher
+ * framework (if needing to pass through an intent or such) and one used in Launcher
*/
@JvmStatic
fun getShellShareableInstanceId(): Pair<com.android.internal.logging.InstanceId, InstanceId> {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index e5d54d7..5214f7c 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -57,8 +57,10 @@
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
+import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskViewUtils;
@@ -79,10 +81,12 @@
private final Context mContext;
private final Handler mHandler;
+ private final RecentsModel mRecentTasksModel;
private StatsLogManager mStatsLogManager;
private final SystemUiProxy mSystemUiProxy;
private final StateManager mStateManager;
- private final DepthController mDepthController;
+ @Nullable
+ private DepthController mDepthController;
private @StagePosition int mStagePosition;
private ItemInfo mItemInfo;
private Intent mInitialTaskIntent;
@@ -103,13 +107,15 @@
private FloatingTaskView mFirstFloatingTaskView;
public SplitSelectStateController(Context context, Handler handler, StateManager stateManager,
- DepthController depthController, StatsLogManager statsLogManager) {
+ DepthController depthController, StatsLogManager statsLogManager,
+ SystemUiProxy systemUiProxy, RecentsModel recentsModel) {
mContext = context;
mHandler = handler;
mStatsLogManager = statsLogManager;
- mSystemUiProxy = SystemUiProxy.INSTANCE.get(mContext);
+ mSystemUiProxy = systemUiProxy;
mStateManager = stateManager;
mDepthController = depthController;
+ mRecentTasksModel = recentsModel;
}
/**
@@ -149,6 +155,51 @@
}
/**
+ * Pulls the list of active Tasks from RecentsModel, and finds the most recently active Task
+ * matching a given ComponentName. Then uses that Task (which could be null) with the given
+ * callback.
+ *
+ * Used in various task-switching or splitscreen operations when we need to check if there is a
+ * currently running Task of a certain type and use the most recent one.
+ */
+ public void findLastActiveTaskAndRunCallback(ComponentKey componentKey,
+ Consumer<Task> callback) {
+ mRecentTasksModel.getTasks(taskGroups -> {
+ Task lastActiveTask = null;
+ // Loop through tasks in reverse, since they are ordered with most-recent tasks last.
+ for (int i = taskGroups.size() - 1; i >= 0; i--) {
+ GroupTask groupTask = taskGroups.get(i);
+ Task task1 = groupTask.task1;
+ if (isInstanceOfComponent(task1, componentKey)) {
+ lastActiveTask = task1;
+ break;
+ }
+ Task task2 = groupTask.task2;
+ if (isInstanceOfComponent(task2, componentKey)) {
+ lastActiveTask = task2;
+ break;
+ }
+ }
+
+ callback.accept(lastActiveTask);
+ });
+ }
+
+ /**
+ * Checks if a given Task is the most recently-active Task of type componentName. Used for
+ * selecting already-running Tasks for splitscreen.
+ */
+ public boolean isInstanceOfComponent(@Nullable Task task, ComponentKey componentKey) {
+ // Exclude the task that is already staged
+ if (task == null || task.key.id == mInitialTaskId) {
+ return false;
+ }
+
+ return task.key.baseIntent.getComponent().equals(componentKey.componentName)
+ && task.key.userId == componentKey.user.getIdentifier();
+ }
+
+ /**
* To be called when the actual tasks ({@link #mInitialTaskId}, {@link #mSecondTaskId}) are
* to be launched. Call after launcher side animations are complete.
*/
@@ -261,8 +312,9 @@
getOppositeStagePosition(stagePosition), splitRatio, adapter,
shellInstanceId);
} else {
- mSystemUiProxy.startIntentsWithLegacyTransition(getPendingIntent(intent1),
- options1.toBundle(), getPendingIntent(intent2), null /* options2 */,
+ mSystemUiProxy.startIntentsWithLegacyTransition(
+ getPendingIntent(intent1), getShortcutInfo(intent1), options1.toBundle(),
+ getPendingIntent(intent2), getShortcutInfo(intent2), null /* options2 */,
stagePosition, splitRatio, adapter, shellInstanceId);
}
}
@@ -271,15 +323,13 @@
private void launchIntentOrShortcut(Intent intent, ActivityOptions options1, int taskId,
@StagePosition int stagePosition, float splitRatio, RemoteTransition remoteTransition,
@Nullable InstanceId shellInstanceId) {
- PendingIntent pendingIntent = getPendingIntent(intent);
- final ShortcutInfo shortcutInfo = getShortcutInfo(intent,
- pendingIntent.getCreatorUserHandle());
+ final ShortcutInfo shortcutInfo = getShortcutInfo(intent);
if (shortcutInfo != null) {
mSystemUiProxy.startShortcutAndTask(shortcutInfo,
options1.toBundle(), taskId, null /* options2 */, stagePosition,
splitRatio, remoteTransition, shellInstanceId);
} else {
- mSystemUiProxy.startIntentAndTask(pendingIntent, options1.toBundle(), taskId,
+ mSystemUiProxy.startIntentAndTask(getPendingIntent(intent), options1.toBundle(), taskId,
null /* options2 */, stagePosition, splitRatio, remoteTransition,
shellInstanceId);
}
@@ -288,15 +338,13 @@
private void launchIntentOrShortcutLegacy(Intent intent, ActivityOptions options1, int taskId,
@StagePosition int stagePosition, float splitRatio, RemoteAnimationAdapter adapter,
@Nullable InstanceId shellInstanceId) {
- PendingIntent pendingIntent = getPendingIntent(intent);
- final ShortcutInfo shortcutInfo = getShortcutInfo(intent,
- pendingIntent.getCreatorUserHandle());
+ final ShortcutInfo shortcutInfo = getShortcutInfo(intent);
if (shortcutInfo != null) {
mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo,
options1.toBundle(), taskId, null /* options2 */, stagePosition,
splitRatio, adapter, shellInstanceId);
} else {
- mSystemUiProxy.startIntentAndTaskWithLegacyTransition(pendingIntent,
+ mSystemUiProxy.startIntentAndTaskWithLegacyTransition(getPendingIntent(intent),
options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio,
adapter, shellInstanceId);
}
@@ -322,7 +370,7 @@
}
@Nullable
- private ShortcutInfo getShortcutInfo(Intent intent, UserHandle userHandle) {
+ private ShortcutInfo getShortcutInfo(Intent intent) {
if (intent == null || intent.getPackage() == null) {
return null;
}
@@ -334,7 +382,7 @@
try {
final Context context = mContext.createPackageContextAsUser(
- intent.getPackage(), 0 /* flags */, userHandle);
+ intent.getPackage(), 0 /* flags */, mUser);
return new ShortcutInfo.Builder(context, shortcutId).build();
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Failed to create a ShortcutInfo for " + intent.getPackage());
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 69f9ce3..0b83eaf 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -157,7 +157,8 @@
mSizeStrategy.calculateGridTaskSize(mContext, mDp, mTaskRect,
mOrientationState.getOrientationHandler());
} else {
- mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
+ mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect,
+ mOrientationState.getOrientationHandler());
}
Rect fullTaskSize;
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
index 01a997a..70a12d6 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
@@ -41,7 +41,8 @@
Hotseat hotseat = mLauncher.getHotseat();
ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
- disableClipping(hotseat);
+ setClipChildren(hotseat, false);
+ setClipToPadding(hotseat, false);
for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
View child = hotseatIcons.getChildAt(i);
@@ -51,7 +52,7 @@
@Override
public void onTransitionFinished() {
- restoreClipping(mLauncher.getHotseat());
+ restoreClippings();
super.onTransitionFinished();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
index 95a4b8f..7da103e 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -47,7 +47,8 @@
final CellLayout cellLayout = (CellLayout) page;
ShortcutAndWidgetContainer itemsContainer = cellLayout
.getShortcutsAndWidgets();
- disableClipping(cellLayout);
+ setClipChildren(cellLayout, false);
+ setClipToPadding(cellLayout, false);
for (int i = 0; i < itemsContainer.getChildCount(); i++) {
View child = itemsContainer.getChildAt(i);
@@ -55,13 +56,13 @@
}
});
- disableClipping(workspace);
+ setClipChildren(workspace, false);
+ setClipToPadding(workspace, true);
}
@Override
public void onTransitionFinished() {
- restoreClipping(mLauncher.getWorkspace());
- mLauncher.getWorkspace().forEachVisiblePage(page -> restoreClipping((CellLayout) page));
+ restoreClippings();
super.onTransitionFinished();
}
}
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index d098ffc..6813857 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -67,7 +67,6 @@
private float mGridTranslationPrimary;
private float mGridScrollOffset;
private float mScrollOffsetPrimary;
- private float mSplitSelectScrollOffsetPrimary;
private int mSidePadding;
@@ -176,10 +175,6 @@
mScrollOffsetPrimary = scrollOffsetPrimary;
}
- public void setSplitSelectScrollOffsetPrimary(float splitSelectScrollOffsetPrimary) {
- mSplitSelectScrollOffsetPrimary = splitSelectScrollOffsetPrimary;
- }
-
public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
float scrollAdjustment = 0;
if (fullscreenEnabled) {
@@ -189,7 +184,6 @@
scrollAdjustment += mGridTranslationPrimary + mGridScrollOffset;
}
scrollAdjustment += mScrollOffsetPrimary;
- scrollAdjustment += mSplitSelectScrollOffsetPrimary;
return scrollAdjustment;
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index dc265e4..14898b1 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -24,6 +24,8 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.os.SystemProperties;
@@ -31,14 +33,16 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
@@ -87,7 +91,8 @@
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
- private ShapeDrawable mBackground;
+ private View mBackgroundView;
+ private View mEmptyView;
public DesktopTaskView(Context context) {
this(context, null);
@@ -104,14 +109,35 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+
+ mBackgroundView = findViewById(R.id.background);
+ mEmptyView = findViewById(R.id.empty_view);
+
+ int topMarginPx =
+ mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ FrameLayout.LayoutParams params = (LayoutParams) mBackgroundView.getLayoutParams();
+ params.topMargin = topMarginPx;
+ mBackgroundView.setLayoutParams(params);
+
float[] outerRadii = new float[8];
Arrays.fill(outerRadii, getTaskCornerRadius());
RoundRectShape shape = new RoundRectShape(outerRadii, null, null);
- mBackground = new ShapeDrawable(shape);
- mBackground.setTint(getResources().getColor(android.R.color.system_neutral2_300,
+ ShapeDrawable background = new ShapeDrawable(shape);
+ background.setTint(getResources().getColor(android.R.color.system_neutral2_300,
getContext().getTheme()));
// TODO(b/244348395): this should be wallpaper
- setBackground(mBackground);
+ mBackgroundView.setBackground(background);
+
+ Drawable icon = getResources().getDrawable(R.drawable.ic_desktop, getContext().getTheme());
+ Drawable iconBackground = getResources().getDrawable(R.drawable.bg_circle,
+ getContext().getTheme());
+ mIconView.setDrawable(new LayerDrawable(new Drawable[]{iconBackground, icon}));
+ }
+
+ @Override
+ protected void updateBorderBounds(Rect bounds) {
+ bounds.set(mBackgroundView.getLeft(), mBackgroundView.getTop(), mBackgroundView.getRight(),
+ mBackgroundView.getBottom());
}
@Override
@@ -161,6 +187,8 @@
mSnapshotViewMap.put(task.key.id, snapshotView);
}
+ mEmptyView.setVisibility(mTasks.isEmpty() ? View.VISIBLE : View.GONE);
+
updateTaskIdContainer();
updateTaskIdAttributeContainer();
@@ -252,20 +280,9 @@
}
@Override
- public void setOrientationState(RecentsOrientedState orientationState) {
- // TODO(b/249371338): this copies logic from TaskView
- PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
- boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-
- LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
-
int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
- int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
- int taskMargin = deviceProfile.overviewTaskMarginPx;
-
- orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
- thumbnailTopMargin, isRtl);
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
@@ -364,6 +381,7 @@
}
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
+ setVisibility(VISIBLE);
}
@Override
@@ -374,6 +392,9 @@
setMeasuredDimension(containerWidth, containerHeight);
+ int thumbnailTopMarginPx = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ containerHeight -= thumbnailTopMarginPx;
+
int thumbnails = mSnapshotViewMap.size();
if (thumbnails == 0) {
return;
@@ -416,6 +437,8 @@
}
int taskX = (int) (positionInParent.x * scaleWidth);
int taskY = (int) (positionInParent.y * scaleHeight);
+ // move task down by margin size
+ taskY += thumbnailTopMarginPx;
thumbnailView.setX(taskX);
thumbnailView.setY(taskY);
@@ -439,9 +462,9 @@
mFullscreenProgress = progress;
if (mFullscreenProgress > 0) {
// Don't show background while we are transitioning to/from fullscreen
- setBackground(null);
+ mBackgroundView.setVisibility(INVISIBLE);
} else {
- setBackground(mBackground);
+ mBackgroundView.setVisibility(VISIBLE);
}
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 3f7d677..e9498fd 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -5,6 +5,7 @@
import android.content.Context;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -72,6 +73,23 @@
}
@Override
+ protected void updateBorderBounds(Rect bounds) {
+ if (mSplitBoundsConfig == null) {
+ super.updateBorderBounds(bounds);
+ return;
+ }
+ bounds.set(
+ Math.min(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
+ mSnapshotView2.getLeft() + Math.round(mSnapshotView2.getTranslationX())),
+ Math.min(mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
+ mSnapshotView2.getTop() + Math.round(mSnapshotView2.getTranslationY())),
+ Math.max(mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
+ mSnapshotView2.getRight() + Math.round(mSnapshotView2.getTranslationX())),
+ Math.max(mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()),
+ mSnapshotView2.getBottom() + Math.round(mSnapshotView2.getTranslationY())));
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
mSnapshotView2 = findViewById(R.id.bottomright_snapshot);
@@ -355,6 +373,12 @@
mSnapshotView2.setSplashAlpha(mTaskThumbnailSplashAlpha);
}
+ @Override
+ protected void refreshTaskThumbnailSplash() {
+ super.refreshTaskThumbnailSplash();
+ mSnapshotView2.refreshSplashView();
+ }
+
/**
* Sets visibility for thumbnails and associated elements (DWB banners).
* IconView is unaffected.
diff --git a/quickstep/src/com/android/quickstep/views/LaunchableConstraintLayout.kt b/quickstep/src/com/android/quickstep/views/LaunchableConstraintLayout.kt
new file mode 100644
index 0000000..537eca1
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/LaunchableConstraintLayout.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.systemui.animation.LaunchableView
+import com.android.systemui.animation.LaunchableViewDelegate
+
+/** A [ConstraintLayout] that also implements [LaunchableView]. */
+open class LaunchableConstraintLayout : ConstraintLayout, LaunchableView {
+ private val delegate =
+ LaunchableViewDelegate(
+ this,
+ superSetVisibility = { super.setVisibility(it) },
+ )
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ defStyleRes: Int,
+ ) : super(context, attrs, defStyleAttr, defStyleRes)
+
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {
+ delegate.setShouldBlockVisibilityChanges(block)
+ }
+
+ override fun setVisibility(visibility: Int) {
+ // Note that super.setVisibility() is passed to the delegate upon creation and called by it.
+ // This method is just a passthrough if no animation is in progress, whereas otherwise it
+ // caches the passed value and restores it at the end of the animation.
+ delegate.setVisibility(visibility)
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 886fc80..c165acc 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep.views;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -41,8 +43,10 @@
import com.android.launcher3.util.PendingSplitSelectInfo;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
+import com.android.quickstep.GestureState;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RotationTouchHelper;
+import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.systemui.shared.recents.model.Task;
@@ -92,6 +96,7 @@
@Override
public void onTaskIconChanged(int taskId) {
+ super.onTaskIconChanged(taskId);
// If Launcher needs to return to split select state, do it now, after the icon has updated.
if (mActivity.hasPendingSplitSelectInfo()) {
PendingSplitSelectInfo recoveryData = mActivity.getPendingSplitSelectInfo();
@@ -168,8 +173,9 @@
}
@Override
- public void setModalStateEnabled(boolean isModalState, boolean animate) {
- if (isModalState) {
+ public void setModalStateEnabled(int taskId, boolean animate) {
+ if (taskId != INVALID_TASK_ID) {
+ setSelectedTask(taskId);
mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK, animate);
} else {
if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
@@ -222,11 +228,23 @@
@Override
public void onGestureAnimationEnd() {
+ DesktopVisibilityController desktopVisibilityController = null;
+ boolean showDesktopApps = false;
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ desktopVisibilityController = mActivity.getDesktopVisibilityController();
+ if (mCurrentGestureEndTarget == GestureState.GestureEndTarget.LAST_TASK
+ && desktopVisibilityController.areFreeformTasksVisible()) {
+ // Recents gesture was cancelled and we are returning to the previous task.
+ // After super class has handled clean up, show desktop apps on top again
+ showDesktopApps = true;
+ }
+ }
super.onGestureAnimationEnd();
- DesktopVisibilityController desktopVisibilityController =
- mActivity.getDesktopVisibilityController();
if (desktopVisibilityController != null) {
desktopVisibilityController.setGestureInProgress(false);
}
+ if (showDesktopApps) {
+ SystemUiProxy.INSTANCE.get(mActivity).showDesktopApps();
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 0d21e60..409504b 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -56,7 +56,8 @@
HIDDEN_NO_RECENTS,
HIDDEN_SPLIT_SCREEN,
HIDDEN_SPLIT_SELECT_ACTIVE,
- HIDDEN_ACTIONS_IN_MENU
+ HIDDEN_ACTIONS_IN_MENU,
+ HIDDEN_DESKTOP
})
@Retention(RetentionPolicy.SOURCE)
public @interface ActionsHiddenFlags { }
@@ -67,6 +68,7 @@
public static final int HIDDEN_SPLIT_SCREEN = 1 << 3;
public static final int HIDDEN_SPLIT_SELECT_ACTIVE = 1 << 4;
public static final int HIDDEN_ACTIONS_IN_MENU = 1 << 5;
+ public static final int HIDDEN_DESKTOP = 1 << 6;
@IntDef(flag = true, value = {
DISABLED_SCROLLING,
@@ -259,26 +261,8 @@
* Offsets OverviewActionsView horizontal position based on 3 button nav container in taskbar.
*/
private void updatePadding() {
- if (mDp == null) {
- return;
- }
- boolean largeScreenLandscape = mDp.isTablet && !mDp.isTwoPanels && mDp.isLandscape;
- // If in 3-button mode, shift action buttons to accommodate 3-button layout.
- // (Special exception for landscape tablets, where there is enough room and we don't need to
- // shift the action buttons.)
- if (mDp.areNavButtonsInline && !largeScreenLandscape
- // If taskbar is in overview, overview action has dedicated space above nav buttons
- && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
- // Add extra horizontal spacing
- int additionalPadding = mDp.hotseatBarEndOffset;
- if (isLayoutRtl()) {
- setPadding(mInsets.left + additionalPadding, 0, mInsets.right, 0);
- } else {
- setPadding(mInsets.left, 0, mInsets.right + additionalPadding, 0);
- }
- } else {
- setPadding(mInsets.left, 0, mInsets.right, 0);
- }
+ // If taskbar is in overview, overview action has dedicated space above nav buttons
+ setPadding(mInsets.left, 0, mInsets.right, 0);
}
/** Updates vertical margins for different navigation mode or configuration changes. */
@@ -298,9 +282,8 @@
return 0;
}
- if (!mDp.isGestureMode && mDp.isTaskbarPresent
- && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
- return mDp.getOverviewActionsClaimedSpaceBelow();
+ if (mDp.isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
+ return mDp.stashedTaskbarSize;
}
// Align to bottom of task Rect.
@@ -318,7 +301,7 @@
requestLayout();
- mSplitButton.setCompoundDrawablesWithIntrinsicBounds(
+ mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
(dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical),
0, 0, 0);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 0f7c8af..16935c1 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -44,7 +44,6 @@
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCH_FROM_STAGED_APP;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_ACTIONS_SPLIT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
@@ -53,8 +52,6 @@
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.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
@@ -62,6 +59,7 @@
import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
+import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
@@ -79,7 +77,6 @@
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.WindowConfiguration;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.LocusId;
@@ -453,6 +450,8 @@
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
protected final Rect mLastComputedGridTaskSize = new Rect();
+ protected final Rect mLastComputedDesktopTaskSize = new Rect();
+ private TaskView mSelectedTask = null;
// How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
@Nullable
protected Float mLastComputedTaskStartPushOutDistance = null;
@@ -516,6 +515,7 @@
private float mTaskThumbnailSplashAlpha = 0;
private boolean mShowAsGridLastOnLayout = false;
private final IntSet mTopRowIdSet = new IntSet();
+ private int mClearAllShortTotalWidthTranslation = 0;
// The GestureEndTarget that is still in progress.
@Nullable
@@ -706,6 +706,12 @@
private ObjectAnimator mActionsViewAlphaAnimator;
private float mActionsViewAlphaAnimatorFinalValue;
+ /**
+ * Keeps track of the desktop task. Optional and only present when the feature flag is enabled.
+ */
+ @Nullable
+ private DesktopTaskView mDesktopTaskView;
+
private MultiWindowModeChangedListener mMultiWindowModeChangedListener =
new MultiWindowModeChangedListener() {
@Override
@@ -956,6 +962,14 @@
}
}
+ @Override
+ public void onTaskIconChanged(int taskId) {
+ TaskView taskView = getTaskViewByTaskId(taskId);
+ if (taskView != null) {
+ taskView.refreshTaskThumbnailSplash();
+ }
+ }
+
/**
* Update the thumbnail of the task.
* @param refreshNow Refresh immediately if it's true.
@@ -1076,6 +1090,16 @@
super.draw(canvas);
}
+ @Override
+ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
+ if (isModal()) {
+ // Do not scroll when clicking on a modal grid task, as it will already be centered
+ // on screen.
+ return false;
+ }
+ return super.requestChildRectangleOnScreen(child, rectangle, immediate);
+ }
+
public void addSideTaskLaunchCallback(RunnableList callback) {
if (mSideTaskLaunchCallback == null) {
mSideTaskLaunchCallback = new RunnableList();
@@ -1214,21 +1238,9 @@
return clearAllScroll + (mIsRtl ? distance : -distance);
}
- private int getSnapToFocusedTaskScrollDiff(boolean isClearAllHidden) {
- int screenStart = mOrientationHandler.getPrimaryScroll(this);
- int targetScroll = getScrollForPage(indexOfChild(getFocusedTaskView()));
- if (!isClearAllHidden) {
- int clearAllWidth = mOrientationHandler.getPrimarySize(mClearAllButton);
- int taskGridHorizontalDiff = mLastComputedTaskSize.right - mLastComputedGridSize.right;
- int clearAllFocusScrollDiff = taskGridHorizontalDiff - clearAllWidth;
- targetScroll += mIsRtl ? clearAllFocusScrollDiff : -clearAllFocusScrollDiff;
- }
- return screenStart - targetScroll;
- }
-
private boolean isTaskViewWithinBounds(TaskView tv, int start, int end) {
int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
- showAsFullscreen(), showAsGrid());
+ showAsGrid());
int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
showAsFullscreen()));
int taskEnd = taskStart + taskSize;
@@ -1238,7 +1250,7 @@
private boolean isTaskViewFullyWithinBounds(TaskView tv, int start, int end) {
int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
- showAsFullscreen(), showAsGrid());
+ showAsGrid());
int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
showAsFullscreen()));
int taskEnd = taskStart + taskSize;
@@ -1264,7 +1276,7 @@
*/
@Nullable
public TaskView getTaskViewByTaskId(int taskId) {
- if (taskId == -1) {
+ if (taskId == INVALID_TASK_ID) {
return null;
}
@@ -1277,53 +1289,6 @@
return null;
}
- /**
- * Pulls the list of active Tasks from RecentsModel, and finds the most recently active Task
- * matching a given ComponentName. Then uses that Task (which could be null) with the given
- * callback.
- *
- * Used in various task-switching or splitscreen operations when we need to check if there is a
- * currently running Task of a certain type and use the most recent one.
- */
- public void findLastActiveTaskAndRunCallback(ComponentName componentName,
- Consumer<Task> callback) {
- mModel.getTasks(taskGroups -> {
- Task lastActiveTask = null;
- // Loop through tasks in reverse, since they are ordered with most-recent tasks last.
- for (int i = taskGroups.size() - 1; i >= 0; i--) {
- GroupTask groupTask = taskGroups.get(i);
- Task task1 = groupTask.task1;
- if (isInstanceOfComponent(task1, componentName)) {
- lastActiveTask = task1;
- break;
- }
- Task task2 = groupTask.task2;
- if (isInstanceOfComponent(task2, componentName)) {
- lastActiveTask = task2;
- break;
- }
- }
-
- callback.accept(lastActiveTask);
- });
- }
-
- /**
- * Checks if a given Task is the most recently-active Task of type componentName. Used for
- * selecting already-running Tasks for splitscreen.
- */
- public boolean isInstanceOfComponent(@Nullable Task task, ComponentName componentName) {
- if (task == null) {
- return false;
- }
- // Exclude the task that is already staged
- if (mSplitHiddenTaskView != null && mSplitHiddenTaskView.getTask().equals(task)) {
- return false;
- }
-
- return task.key.baseIntent.getComponent().equals(componentName);
- }
-
public void setOverviewStateEnabled(boolean enabled) {
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
@@ -1521,20 +1486,20 @@
}
/**
- * Moves the focused task to the front of the carousel in tablets, to minimize animation
- * required to focus the task in grid.
+ * Moves the running task to the front of the carousel in tablets, to minimize animation
+ * required to move the running task in grid.
*/
- public void moveFocusedTaskToFront() {
+ public void moveRunningTaskToFront() {
if (!mActivity.getDeviceProfile().isTablet) {
return;
}
- TaskView focusedTaskView = getFocusedTaskView();
- if (focusedTaskView == null) {
+ TaskView runningTaskView = getRunningTaskView();
+ if (runningTaskView == null) {
return;
}
- if (indexOfChild(focusedTaskView) != mCurrentPage) {
+ if (indexOfChild(runningTaskView) != mCurrentPage) {
return;
}
@@ -1546,20 +1511,20 @@
int currentPageScroll = getScrollForPage(mCurrentPage);
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
- mMovingTaskView = focusedTaskView;
- removeView(focusedTaskView);
+ mMovingTaskView = runningTaskView;
+ removeView(runningTaskView);
mMovingTaskView = null;
- focusedTaskView.resetPersistentViewTransforms();
+ runningTaskView.resetPersistentViewTransforms();
int frontTaskIndex = 0;
- if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED && !focusedTaskView.isDesktopTask()) {
+ if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED && !runningTaskView.isDesktopTask()) {
// If desktop mode is enabled, desktop task view is pinned at first position.
- // Move focused task to position 1
+ // Move running task to position 1
frontTaskIndex = 1;
}
- addView(focusedTaskView, frontTaskIndex);
+ addView(runningTaskView, frontTaskIndex);
setCurrentPage(frontTaskIndex);
- updateGridProperties();
+ updateTaskSize();
}
@Override
@@ -1592,7 +1557,7 @@
return;
}
- int currentTaskId = -1;
+ int currentTaskId = INVALID_TASK_ID;
TaskView currentTaskView = getTaskViewAt(mCurrentPage);
if (currentTaskView != null && currentTaskView.getTask() != null) {
currentTaskId = currentTaskView.getTask().key.id;
@@ -1602,7 +1567,8 @@
unloadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
TaskView ignoreResetTaskView =
- mIgnoreResetTaskId == -1 ? null : getTaskViewByTaskId(mIgnoreResetTaskId);
+ mIgnoreResetTaskId == INVALID_TASK_ID
+ ? null : getTaskViewByTaskId(mIgnoreResetTaskId);
// Save running task ID if it exists before rebinding all taskViews, otherwise the task from
// the runningTaskView currently bound could get assigned to another TaskView
@@ -1616,13 +1582,18 @@
// If we are entering Overview as a result of initiating a split from somewhere else
// (e.g. split from Home), we need to make sure the staged app is not drawn as a thumbnail.
- int stagedTaskIdToBeRemovedFromGrid = mSplitSelectSource != null
- ? mSplitSelectSource.alreadyRunningTaskId
- : INVALID_TASK_ID;
-
+ int stagedTaskIdToBeRemovedFromGrid;
+ if (mSplitSelectSource != null) {
+ stagedTaskIdToBeRemovedFromGrid = mSplitSelectSource.alreadyRunningTaskId;
+ updateCurrentTaskActionsVisibility();
+ } else {
+ stagedTaskIdToBeRemovedFromGrid = INVALID_TASK_ID;
+ }
// update the map of instance counts
mFilterState.updateInstanceCountMap(taskGroups);
+ // Clear out desktop view if it is set
+ mDesktopTaskView = null;
DesktopTask desktopTask = null;
// Add views as children based on whether it's grouped or single task. Looping through
@@ -1681,12 +1652,13 @@
if (!taskGroups.isEmpty()) {
addView(mClearAllButton);
- if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
- TaskView taskView = getTaskViewFromPool(TaskView.Type.DESKTOP);
+ if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED
+ && !getSplitSelectController().isSplitSelectActive()) {
+ mDesktopTaskView = (DesktopTaskView) getTaskViewFromPool(TaskView.Type.DESKTOP);
// Always add a desktop task to the first position. Even if it is empty
- addView(taskView, 0);
+ addView(mDesktopTaskView, 0);
ArrayList<Task> tasks = desktopTask != null ? desktopTask.tasks : new ArrayList<>();
- ((DesktopTaskView) taskView).bind(tasks, mOrientationState);
+ mDesktopTaskView.bind(tasks, mOrientationState);
}
}
@@ -1702,20 +1674,20 @@
newFocusedTaskView = getTaskViewAt(1);
}
}
- mFocusedTaskViewId = newFocusedTaskView != null ?
- newFocusedTaskView.getTaskViewId() : -1;
+ mFocusedTaskViewId = newFocusedTaskView != null && !ENABLE_GRID_ONLY_OVERVIEW.get()
+ ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID;
updateTaskSize();
updateChildTaskOrientations();
TaskView newRunningTaskView = null;
- if (runningTaskId != -1) {
+ if (runningTaskId != INVALID_TASK_ID) {
// Update mRunningTaskViewId to be the new TaskView that was assigned by binding
// the full list of tasks to taskViews
newRunningTaskView = getTaskViewByTaskId(runningTaskId);
if (newRunningTaskView != null) {
mRunningTaskViewId = newRunningTaskView.getTaskViewId();
} else {
- mRunningTaskViewId = -1;
+ mRunningTaskViewId = INVALID_TASK_ID;
}
}
@@ -1723,7 +1695,7 @@
if (mNextPage != INVALID_PAGE) {
// Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll.
mCurrentPage = previousCurrentPage;
- if (currentTaskId != -1) {
+ if (currentTaskId != INVALID_TASK_ID) {
currentTaskView = getTaskViewByTaskId(currentTaskId);
if (currentTaskView != null) {
targetPage = indexOfChild(currentTaskView);
@@ -1731,7 +1703,7 @@
}
} else {
// Set the current page to the running task, but not if settling on new task.
- if (runningTaskId != -1) {
+ if (runningTaskId != INVALID_TASK_ID) {
targetPage = indexOfChild(newRunningTaskView);
} else if (getTaskViewCount() > 0) {
TaskView taskView = requireTaskViewAt(0);
@@ -1757,12 +1729,12 @@
});
}
- if (mIgnoreResetTaskId != -1 &&
+ if (mIgnoreResetTaskId != INVALID_TASK_ID &&
getTaskViewByTaskId(mIgnoreResetTaskId) != ignoreResetTaskView) {
// If the taskView mapping is changing, do not preserve the visuals. Since we are
// mostly preserving the first task, and new taskViews are added to the end, it should
// generally map to the same task.
- mIgnoreResetTaskId = -1;
+ mIgnoreResetTaskId = INVALID_TASK_ID;
}
resetTaskVisuals();
onTaskStackUpdated();
@@ -1818,7 +1790,7 @@
* Returns the number of tasks in the bottom row of the overview grid.
*/
public int getBottomRowTaskCountForTablet() {
- return getTaskViewCount() - mTopRowIdSet.size() - 1;
+ return getTaskViewCount() - mTopRowIdSet.size() - (ENABLE_GRID_ONLY_OVERVIEW.get() ? 0 : 1);
}
protected void onTaskStackUpdated() {
@@ -1956,7 +1928,7 @@
private void onOrientationChanged() {
// If overview is in modal state when rotate, reset it to overview state without running
// animation.
- setModalStateEnabled(/* isModalState= */ false, /* animate= */ false);
+ setModalStateEnabled(/* taskId= */ INVALID_TASK_ID, /* animate= */ false);
if (isSplitSelectionActive()) {
onRotateInSplitSelectionState();
}
@@ -1978,6 +1950,10 @@
mLastComputedGridSize);
mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
mLastComputedGridTaskSize, mOrientationHandler);
+ if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+ mSizeStrategy.calculateDesktopTaskSize(mActivity, mActivity.getDeviceProfile(),
+ mLastComputedDesktopTaskSize);
+ }
mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
mTopBottomRowHeightDiff =
@@ -2024,17 +2000,39 @@
}
public void getTaskSize(Rect outRect) {
- mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
+ mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
+ mOrientationHandler);
mLastComputedTaskSize.set(outRect);
}
/**
- * Returns the size of task selected to enter modal state.
+ * Sets the last TaskView selected.
*/
- public Point getSelectedTaskSize() {
- mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(),
- mTempRect);
- return new Point(mTempRect.width(), mTempRect.height());
+ public void setSelectedTask(int lastSelectedTaskId) {
+ mSelectedTask = getTaskViewByTaskId(lastSelectedTaskId);
+ }
+
+ /**
+ * Returns the bounds of the task selected to enter modal state.
+ */
+ public Rect getSelectedTaskBounds() {
+ if (mSelectedTask == null) {
+ return mLastComputedTaskSize;
+ }
+ return getTaskBounds(mSelectedTask);
+ }
+
+ private Rect getTaskBounds(TaskView taskView) {
+ int selectedPage = indexOfChild(taskView);
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+ int selectedPageScroll = getScrollForPage(selectedPage);
+ boolean isTopRow = taskView != null && mTopRowIdSet.contains(taskView.getTaskViewId());
+ Rect outRect = new Rect(mLastComputedTaskSize);
+ outRect.offset(
+ -(primaryScroll - (selectedPageScroll + getOffsetFromScrollPosition(selectedPage))),
+ (int) (showAsGrid() && ENABLE_GRID_ONLY_OVERVIEW.get() && !isTopRow
+ ? mTopBottomRowHeightDiff : 0));
+ return outRect;
}
/** Gets the last computed task size */
@@ -2046,9 +2044,15 @@
return mLastComputedGridTaskSize;
}
+ /** Gets the last computed desktop task size */
+ public Rect getLastComputedDesktopTaskSize() {
+ return mLastComputedDesktopTaskSize;
+ }
+
/** Gets the task size for modal state. */
public void getModalTaskSize(Rect outRect) {
- mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
+ mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
+ mOrientationHandler);
}
@Override
@@ -2481,8 +2485,7 @@
for (TaskViewSimulator tvs : taskViewSimulators) {
if (animatorSet == null) {
setGridProgress(1);
- tvs.taskPrimaryTranslation.value =
- runningTaskPrimaryGridTranslation;
+ tvs.taskPrimaryTranslation.value = runningTaskPrimaryGridTranslation;
} else {
animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
@@ -2591,7 +2594,7 @@
boolean runningTaskTileHidden = mRunningTaskTileHidden;
setCurrentTask(runningTaskViewId);
- mFocusedTaskViewId = runningTaskViewId;
+ mFocusedTaskViewId = ENABLE_GRID_ONLY_OVERVIEW.get() ? INVALID_TASK_ID : runningTaskViewId;
runOnPageScrollsInitialized(() -> setCurrentPage(getRunningTaskIndex()));
setRunningTaskViewShowScreenshot(false);
setRunningTaskHidden(runningTaskTileHidden);
@@ -2724,7 +2727,8 @@
return;
}
- int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ int taskTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
int topRowWidth = 0;
int bottomRowWidth = 0;
@@ -2779,10 +2783,17 @@
} else if (taskView.isDesktopTask()) {
// Desktop task was not focused. Pin it to the right of focused
desktopTaskIndex = i;
- gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
+ if (taskView.getVisibility() == View.GONE) {
+ // Desktop task view is hidden, skip it from grid calculations
+ continue;
+ }
+ if (!ENABLE_GRID_ONLY_OVERVIEW.get()) {
+ // Only apply x-translation when using legacy overview grid
+ gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
+ }
// Center view vertically in case it's from different orientation.
- taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
+ taskView.setGridTranslationY((mLastComputedDesktopTaskSize.height() + taskTopMargin
- taskView.getLayoutParams().height) / 2f);
} else {
if (i > focusedTaskIndex) {
@@ -2866,7 +2877,7 @@
float snappedTaskGridTranslationX = 0;
if (snappedTaskView != null) {
snappedTaskNonGridScrollAdjustment = snappedTaskView.getScrollAdjustment(
- /*fullscreenEnabled=*/true, /*gridEnabled=*/false);
+ /*gridEnabled=*/false);
snappedTaskGridTranslationX = gridTranslations[snappedPage];
}
@@ -2891,18 +2902,28 @@
// If the total width is shorter than one grid's width, move ClearAllButton further away
// accordingly. Update longRowWidth if ClearAllButton has been moved.
- float clearAllShortTotalCompensation = 0;
+ float clearAllShortTotalWidthTranslation = 0;
int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
if (longRowWidth < mLastComputedGridSize.width()) {
- float shortTotalCompensation = mLastComputedGridSize.width() - longRowWidth;
- clearAllShortTotalCompensation =
- mIsRtl ? -shortTotalCompensation : shortTotalCompensation;
- longRowWidth = mLastComputedGridSize.width();
+ mClearAllShortTotalWidthTranslation =
+ (mIsRtl
+ ? mLastComputedTaskSize.right
+ : deviceProfile.widthPx - mLastComputedTaskSize.left)
+ - longRowWidth - deviceProfile.overviewGridSideMargin;
+ clearAllShortTotalWidthTranslation = mIsRtl
+ ? -mClearAllShortTotalWidthTranslation : mClearAllShortTotalWidthTranslation;
+ if (snappedTaskRowWidth == longRowWidth) {
+ // Updated snappedTaskRowWidth as well if it's same as longRowWidth.
+ snappedTaskRowWidth += mClearAllShortTotalWidthTranslation;
+ }
+ longRowWidth += mClearAllShortTotalWidthTranslation;
+ } else {
+ mClearAllShortTotalWidthTranslation = 0;
}
float clearAllTotalTranslationX =
clearAllAccumulatedTranslation + clearAllShorterRowCompensation
- + clearAllShortTotalCompensation + snappedTaskNonGridScrollAdjustment;
+ + clearAllShortTotalWidthTranslation + snappedTaskNonGridScrollAdjustment;
if (focusedTaskIndex < taskCount) {
// Shift by focused task's width and spacing if a task is focused.
clearAllTotalTranslationX +=
@@ -2912,11 +2933,15 @@
// Make sure there are enough space between snapped page and ClearAllButton, for the case
// of swiping up after quick switch.
if (snappedTaskView != null) {
- int distanceFromClearAll = longRowWidth - snappedTaskRowWidth + mPageSpacing;
+ int distanceFromClearAll = longRowWidth - snappedTaskRowWidth;
// ClearAllButton should be off screen when snapped task is in its snapped position.
int minimumDistance =
- mTaskWidth - snappedTaskView.getLayoutParams().width
- + (mLastComputedGridSize.width() - mTaskWidth) / 2;
+ (mIsRtl
+ ? mLastComputedTaskSize.left
+ : deviceProfile.widthPx - mLastComputedTaskSize.right)
+ - deviceProfile.overviewGridSideMargin - mPageSpacing
+ + (mTaskWidth - snappedTaskView.getLayoutParams().width)
+ - mClearAllShortTotalWidthTranslation;
if (distanceFromClearAll < minimumDistance) {
int distanceDifference = minimumDistance - distanceFromClearAll;
snappedTaskGridTranslationX += mIsRtl ? distanceDifference : -distanceDifference;
@@ -3199,6 +3224,7 @@
// Grid specific properties.
boolean isFocusedTaskDismissed = false;
+ boolean isStagingFocusedTask = false;
TaskView nextFocusedTaskView = null;
boolean nextFocusedTaskFromTop = false;
float dismissedTaskWidth = 0;
@@ -3213,26 +3239,30 @@
if (showAsGrid) {
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
- if (isFocusedTaskDismissed && !isSplitSelectionActive()) {
- nextFocusedTaskFromTop =
- mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
- // Pick the next focused task from the preferred row.
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
- if (taskView == dismissedTaskView) {
- continue;
+ if (isFocusedTaskDismissed) {
+ if (isSplitSelectionActive()) {
+ isStagingFocusedTask = true;
+ } else {
+ nextFocusedTaskFromTop =
+ mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
+ // Pick the next focused task from the preferred row.
+ for (int i = 0; i < taskCount; i++) {
+ TaskView taskView = requireTaskViewAt(i);
+ if (taskView == dismissedTaskView) {
+ continue;
+ }
+ boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
+ if ((nextFocusedTaskFromTop && isTopRow
+ || (!nextFocusedTaskFromTop && !isTopRow))) {
+ nextFocusedTaskView = taskView;
+ break;
+ }
}
- boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
- if ((nextFocusedTaskFromTop && isTopRow
- || (!nextFocusedTaskFromTop && !isTopRow))) {
- nextFocusedTaskView = taskView;
- break;
+ if (nextFocusedTaskView != null) {
+ nextFocusedTaskWidth =
+ nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
}
}
- if (nextFocusedTaskView != null) {
- nextFocusedTaskWidth =
- nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
- }
}
} else {
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
@@ -3249,8 +3279,6 @@
boolean snapToLastTask = false;
boolean isLandscapeSplit =
mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
- boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
- boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
int currentPageScroll = getScrollForPage(mCurrentPage);
int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
@@ -3262,42 +3290,69 @@
float longGridRowWidthDiff = 0;
int topGridRowSize = mTopRowIdSet.size();
- int bottomGridRowSize = taskCount - mTopRowIdSet.size() - 1;
+ int bottomGridRowSize = taskCount - mTopRowIdSet.size()
+ - (ENABLE_GRID_ONLY_OVERVIEW.get() ? 0 : 1);
boolean topRowLonger = topGridRowSize > bottomGridRowSize;
boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
boolean dismissedTaskFromTop = mTopRowIdSet.contains(dismissedTaskViewId);
boolean dismissedTaskFromBottom = !dismissedTaskFromTop && !isFocusedTaskDismissed;
+ if (dismissedTaskFromTop || (isFocusedTaskDismissed && nextFocusedTaskFromTop)) {
+ topGridRowSize--;
+ }
+ if (dismissedTaskFromBottom || (isFocusedTaskDismissed && !nextFocusedTaskFromTop)) {
+ bottomGridRowSize--;
+ }
+ int longRowWidth = Math.max(topGridRowSize, bottomGridRowSize)
+ * (mLastComputedGridTaskSize.width() + mPageSpacing);
+ if (!ENABLE_GRID_ONLY_OVERVIEW.get() && !isStagingFocusedTask) {
+ longRowWidth += mLastComputedTaskSize.width() + mPageSpacing;
+ }
+
float gapWidth = 0;
if ((topRowLonger && dismissedTaskFromTop)
|| (bottomRowLonger && dismissedTaskFromBottom)) {
gapWidth = dismissedTaskWidth;
- } else if ((topRowLonger && nextFocusedTaskFromTop)
- || (bottomRowLonger && !nextFocusedTaskFromTop)) {
+ } else if (nextFocusedTaskView != null
+ && ((topRowLonger && nextFocusedTaskFromTop)
+ || (bottomRowLonger && !nextFocusedTaskFromTop))) {
gapWidth = nextFocusedTaskWidth;
}
if (gapWidth > 0) {
- if (taskCount > 2) {
- // Compensate the removed gap.
- longGridRowWidthDiff += mIsRtl ? -gapWidth : gapWidth;
- if (isClearAllHidden) {
- // If ClearAllButton isn't fully shown, snap to the last task.
- snapToLastTask = true;
+ if (mClearAllShortTotalWidthTranslation == 0) {
+ // Compensate the removed gap if we don't already have shortTotalCompensation,
+ // and adjust accordingly to the new shortTotalCompensation after dismiss.
+ int newClearAllShortTotalWidthTranslation = 0;
+ if (longRowWidth < mLastComputedGridSize.width()) {
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ newClearAllShortTotalWidthTranslation =
+ (mIsRtl
+ ? mLastComputedTaskSize.right
+ : deviceProfile.widthPx - mLastComputedTaskSize.left)
+ - longRowWidth - deviceProfile.overviewGridSideMargin;
}
- } else {
- // If only focused task will be left, snap to focused task instead.
- longGridRowWidthDiff += getSnapToFocusedTaskScrollDiff(isClearAllHidden);
+ float gapCompensation = gapWidth - newClearAllShortTotalWidthTranslation;
+ longGridRowWidthDiff += mIsRtl ? -gapCompensation : gapCompensation;
+ }
+ if (isClearAllHidden) {
+ // If ClearAllButton isn't fully shown, snap to the last task.
+ snapToLastTask = true;
}
}
- if (mClearAllButton.getAlpha() != 0f && isLandscapeSplit) {
- // ClearAllButton will not be available in split select, snap to last task instead.
- snapToLastTask = true;
+ if (isLandscapeSplit && !isStagingFocusedTask) {
+ // LastTask's scroll is the minimum scroll in split select, if current scroll is
+ // beyond that, we'll need to snap to last task instead.
+ TaskView lastTask = getLastGridTaskView();
+ if (lastTask != null) {
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+ int lastTaskScroll = getScrollForPage(indexOfChild(lastTask));
+ if ((mIsRtl && primaryScroll < lastTaskScroll)
+ || (!mIsRtl && primaryScroll > lastTaskScroll)) {
+ snapToLastTask = true;
+ }
+ }
}
if (snapToLastTask) {
longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
- if (isSplitPlaceholderLastInGrid) {
- // Shift all the tasks to make space for split placeholder.
- longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
- }
} else if (isLandscapeSplit && currentPageSnapsToEndOfGrid) {
// Use last task as reference point for scroll diff and snapping calculation as it's
// the only invariant point in landscape split screen.
@@ -3455,8 +3510,6 @@
// dismissed index or next focused index. Offset successive task dismissal
// durations for a staggered effect.
distanceFromDismissedTask++;
- boolean isStagingFocusedTask =
- isFocusedTaskDismissed && nextFocusedTaskView == null;
int staggerColumn = isStagingFocusedTask
? (int) Math.ceil(distanceFromDismissedTask / 2f)
: distanceFromDismissedTask;
@@ -3512,11 +3565,6 @@
int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
primaryTranslation +=
mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
- if (isSplitPlaceholderFirstInGrid) {
- // Moves less if split placeholder is at the start.
- primaryTranslation +=
- mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
- }
}
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
@@ -3645,14 +3693,6 @@
RecentsView.this);
int currentPageScroll = getScrollForPage(mCurrentPage);
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
- // Compensate for coordinate shift by split placeholder.
- if (isSplitPlaceholderFirstInGrid && !finalSnapToLastTask) {
- mCurrentPageScrollDiff +=
- mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
- } else if (isSplitPlaceholderLastInGrid && finalSnapToLastTask) {
- mCurrentPageScrollDiff +=
- mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
- }
}
}
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
@@ -3666,14 +3706,15 @@
removeViewInLayout(mClearAllButton);
if (isHomeTaskDismissed) {
updateEmptyMessage();
- } else if (!(ENABLE_TASKBAR_IN_OVERVIEW.get() &&
- mSplitSelectStateController.isSplitSelectActive())) {
+ } else if (!mSplitSelectStateController.isSplitSelectActive()) {
startHome();
}
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
- mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
+ mFocusedTaskViewId = ENABLE_GRID_ONLY_OVERVIEW.get()
+ ? INVALID_TASK_ID
+ : finalNextFocusedTaskView.getTaskViewId();
mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
@@ -3692,8 +3733,7 @@
int screenStart = mOrientationHandler.getPrimaryScroll(
RecentsView.this);
int taskStart = mOrientationHandler.getChildStart(taskView)
- + (int) taskView.getOffsetAdjustment(/*fullscreenEnabled=*/
- false, /*gridEnabled=*/ true);
+ + (int) taskView.getOffsetAdjustment(/*gridEnabled=*/ true);
// Rebalance only if there is a maximum gap between the task and the
// screen's edge; this ensures that rebalanced tasks are outside the
@@ -3769,8 +3809,11 @@
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
!mActivity.getDeviceProfile().isTablet);
- mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK,
- !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get() && getTaskViewCount() <= 1);
+ mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
+ if (DESKTOP_MODE_SUPPORTED) {
+ boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
+ mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
+ }
}
/**
@@ -3852,14 +3895,6 @@
REMOVE_TASK_WAIT_FOR_APP_STOP_MS);
}
- /**
- * Returns {@code true} if one of the task thumbnails would intersect/overlap with the
- * {@link #mFirstFloatingTaskView}.
- */
- public boolean shouldShiftThumbnailsForSplitSelect() {
- return !mActivity.getDeviceProfile().isTablet || !mActivity.getDeviceProfile().isLandscape;
- }
-
protected void onDismissAnimationEnds() {
AccessibilityManagerCompat.sendDismissAnimationEndsEventToTest(getContext());
}
@@ -4158,8 +4193,13 @@
private void updatePivots() {
if (mOverviewSelectEnabled) {
- setPivotX(mLastComputedTaskSize.centerX());
- setPivotY(mLastComputedTaskSize.bottom);
+ getModalTaskSize(mTempRect);
+ Rect selectedTaskPosition = getSelectedTaskBounds();
+
+ Utilities.getPivotsForScalingRectToRect(mTempRect, selectedTaskPosition,
+ mTempPointF);
+ setPivotX(mTempPointF.x);
+ setPivotY(mTempPointF.y);
} else {
getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
mActivity.getDeviceProfile(), mTempPointF);
@@ -4172,11 +4212,17 @@
float offset = mAdjacentPageHorizontalOffset;
float modalOffset = ACCEL_0_75.getInterpolation(mTaskModalness);
int count = getChildCount();
+ boolean showAsGrid = showAsGrid();
TaskView runningTask = mRunningTaskViewId == -1 || !mRunningTaskTileHidden
? null : getRunningTaskView();
int midpoint = runningTask == null ? -1 : indexOfChild(runningTask);
int modalMidpoint = getCurrentPage();
+ boolean isModalGridWithoutFocusedTask =
+ showAsGrid && ENABLE_GRID_ONLY_OVERVIEW.get() && mTaskModalness > 0;
+ if (isModalGridWithoutFocusedTask) {
+ modalMidpoint = indexOfChild(mSelectedTask);
+ }
float midpointOffsetSize = 0;
float leftOffsetSize = midpoint - 1 >= 0
@@ -4186,7 +4232,6 @@
? getHorizontalOffsetSize(midpoint + 1, midpoint, offset)
: 0;
- boolean showAsGrid = showAsGrid();
float modalMidpointOffsetSize = 0;
float modalLeftOffsetSize = 0;
float modalRightOffsetSize = 0;
@@ -4214,23 +4259,34 @@
: i < midpoint
? leftOffsetSize
: rightOffsetSize;
+ if (isModalGridWithoutFocusedTask) {
+ gridOffsetSize = getHorizontalOffsetSize(i, modalMidpoint, modalOffset);
+ gridOffsetSize = Math.abs(gridOffsetSize) * (i <= modalMidpoint ? 1 : -1);
+ }
float modalTranslation = i == modalMidpoint
? modalMidpointOffsetSize
: showAsGrid
? gridOffsetSize
: i < modalMidpoint ? modalLeftOffsetSize : modalRightOffsetSize;
- float totalTranslation = translation + modalTranslation;
+ float totalTranslationX = translation + modalTranslation;
View child = getChildAt(i);
- FloatProperty translationProperty = child instanceof TaskView
+ FloatProperty translationPropertyX = child instanceof TaskView
? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
: mOrientationHandler.getPrimaryViewTranslate();
- translationProperty.set(child, totalTranslation);
+ translationPropertyX.set(child, totalTranslationX);
if (mEnableDrawingLiveTile && i == getRunningTaskIndex()) {
runActionOnRemoteHandles(
remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
- .taskPrimaryTranslation.value = totalTranslation);
+ .taskPrimaryTranslation.value = totalTranslationX);
redrawLiveTile();
}
+
+ if (showAsGrid && ENABLE_GRID_ONLY_OVERVIEW.get() && child instanceof TaskView) {
+ float totalTranslationY = getVerticalOffsetSize(i, modalOffset);
+ FloatProperty translationPropertyY =
+ ((TaskView) child).getSecondaryTaskOffsetTranslationProperty();
+ translationPropertyY.set(child, totalTranslationY);
+ }
}
updateCurveProperties();
}
@@ -4328,6 +4384,38 @@
return distanceToOffscreen * offsetProgress;
}
+ /**
+ * Computes the vertical distance to offset a given child such that it is completely offscreen.
+ *
+ * @param offsetProgress From 0 to 1 where 0 means no offset and 1 means offset offscreen.
+ */
+ private float getVerticalOffsetSize(int childIndex, float offsetProgress) {
+ if (offsetProgress == 0 || !(showAsGrid() && ENABLE_GRID_ONLY_OVERVIEW.get())
+ || mSelectedTask == null) {
+ // Don't bother calculating everything below if we won't offset vertically.
+ return 0;
+ }
+
+ // First, get the position of the task relative to the top row.
+ TaskView child = getTaskViewAt(childIndex);
+ Rect taskPosition = getTaskBounds(child);
+
+ boolean isSelectedTaskTopRow = mTopRowIdSet.contains(mSelectedTask.getTaskViewId());
+ boolean isChildTopRow = mTopRowIdSet.contains(child.getTaskViewId());
+ // Whether the task should be shifted to the top.
+ boolean isTopShift = !isSelectedTaskTopRow && isChildTopRow;
+ boolean isBottomShift = isSelectedTaskTopRow && !isChildTopRow;
+
+ // Next, calculate the distance to move the task off screen at scale = 1.
+ float distanceToOffscreen = 0;
+ if (isTopShift) {
+ distanceToOffscreen = -taskPosition.bottom;
+ } else if (isBottomShift) {
+ distanceToOffscreen = mActivity.getDeviceProfile().heightPx - taskPosition.top;
+ }
+ return distanceToOffscreen * offsetProgress;
+ }
+
protected void setTaskViewsResistanceTranslation(float translation) {
mTaskViewsSecondaryTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
@@ -4365,71 +4453,11 @@
}
/**
- * Apply scroll offset to children of RecentsView when entering split select.
- */
- public void applySplitPrimaryScrollOffset() {
- float taskSplitScrollOffsetPrimary = 0f;
- float clearAllSplitScrollOffsetPrimar = 0f;
- if (isSplitPlaceholderFirstInGrid()) {
- taskSplitScrollOffsetPrimary = mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
- } else if (isSplitPlaceholderLastInGrid()) {
- clearAllSplitScrollOffsetPrimar =
- mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
- }
-
- for (int i = 0; i < getTaskViewCount(); i++) {
- requireTaskViewAt(i).setSplitScrollOffsetPrimary(taskSplitScrollOffsetPrimary);
- }
- mClearAllButton.setSplitSelectScrollOffsetPrimary(clearAllSplitScrollOffsetPrimar);
- }
-
- /**
- * Returns if split placeholder is at the beginning of RecentsView. Always returns {@code false}
- * if RecentsView is in portrait or RecentsView isn't shown as grid.
- */
- private boolean isSplitPlaceholderFirstInGrid() {
- if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
- || !isSplitSelectionActive()) {
- return false;
- }
- @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
- return mIsRtl
- ? position == STAGE_POSITION_BOTTOM_OR_RIGHT
- : position == STAGE_POSITION_TOP_OR_LEFT;
- }
-
- /**
- * Returns if split placeholder is at the end of RecentsView. Always returns {@code false} if
- * RecentsView is in portrait or RecentsView isn't shown as grid.
- */
- private boolean isSplitPlaceholderLastInGrid() {
- if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
- || !isSplitSelectionActive()) {
- return false;
- }
- @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
- return mIsRtl
- ? position == STAGE_POSITION_TOP_OR_LEFT
- : position == STAGE_POSITION_BOTTOM_OR_RIGHT;
- }
-
- /**
- * Reset scroll offset on children of RecentsView when exiting split select.
- */
- public void resetSplitPrimaryScrollOffset() {
- for (int i = 0; i < getTaskViewCount(); i++) {
- requireTaskViewAt(i).setSplitScrollOffsetPrimary(0);
- }
- mClearAllButton.setSplitSelectScrollOffsetPrimary(0);
- }
-
- /**
* Resets the visuals when exit modal state.
*/
public void resetModalVisuals() {
- TaskView taskView = getCurrentPageTaskView();
- if (taskView != null) {
- taskView.getThumbnail().getTaskOverlay().resetModalVisuals();
+ if (mSelectedTask != null) {
+ mSelectedTask.getThumbnail().getTaskOverlay().resetModalVisuals();
}
}
@@ -4452,6 +4480,9 @@
mSplitSelectStateController.setAnimateCurrentTaskDismissal(
true /*animateCurrentTaskDismissal*/);
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
+ if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+ updateDesktopTaskVisibility(false /* visible */);
+ }
}
/**
@@ -4468,6 +4499,15 @@
mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
+ if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+ updateDesktopTaskVisibility(false /* visible */);
+ }
+ }
+
+ private void updateDesktopTaskVisibility(boolean visible) {
+ if (mDesktopTaskView != null) {
+ mDesktopTaskView.setVisibility(visible ? VISIBLE : GONE);
+ }
}
/**
@@ -4576,7 +4616,6 @@
return true;
}
- /** TODO(b/181707736) More gracefully handle exiting split selection state */
@SuppressLint("WrongCall")
protected void resetFromSplitSelectionState() {
if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1) {
@@ -4619,6 +4658,9 @@
mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE);
mSplitHiddenTaskView = null;
}
+ if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+ updateDesktopTaskVisibility(true /* visible */);
+ }
}
private void safeRemoveDragLayerView(@Nullable View viewToRemove) {
@@ -4632,14 +4674,29 @@
* Note that the translation can be its primary or secondary dimension.
*/
public float getSplitSelectTranslation() {
- int splitPosition = getSplitSelectController().getActiveSplitStagePosition();
- if (!shouldShiftThumbnailsForSplitSelect()) {
- return 0f;
- }
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+ int splitPosition = getSplitSelectController().getActiveSplitStagePosition();
+ int splitPlaceholderSize =
+ mActivity.getResources().getDimensionPixelSize(R.dimen.split_placeholder_size);
int direction = orientationHandler.getSplitTranslationDirectionFactor(
- splitPosition, mActivity.getDeviceProfile());
- return mActivity.getResources().getDimension(R.dimen.split_placeholder_size) * direction;
+ splitPosition, deviceProfile);
+
+ if (deviceProfile.isTablet && deviceProfile.isLandscape) {
+ // Only shift TaskViews if there is not enough space on the side of
+ // mLastComputedTaskSize to minimize motion.
+ int sideSpace = mIsRtl
+ ? deviceProfile.widthPx - mLastComputedTaskSize.right
+ : mLastComputedTaskSize.left;
+ int extraSpace = splitPlaceholderSize + mPageSpacing - sideSpace;
+ if (extraSpace <= 0f) {
+ return 0f;
+ }
+
+ return extraSpace * direction;
+ }
+
+ return splitPlaceholderSize * direction;
}
protected void onRotateInSplitSelectionState() {
@@ -4661,8 +4718,6 @@
if (mSplitInstructionsView != null) {
mSplitInstructionsView.ensureProperRotation();
}
-
- applySplitPrimaryScrollOffset();
}
private void updateDeadZoneRects() {
@@ -5152,11 +5207,21 @@
}
private int getLastViewIndex() {
- return mDisallowScrollToClearAll
- ? mShowAsGridLastOnLayout
- ? indexOfChild(getLastGridTaskView())
- : getTaskViewCount() - 1
- : indexOfChild(mClearAllButton);
+ if (!mDisallowScrollToClearAll) {
+ return indexOfChild(mClearAllButton);
+ }
+
+ if (!mShowAsGridLastOnLayout) {
+ return getTaskViewCount() - 1;
+ }
+
+ TaskView lastGridTaskView = getLastGridTaskView();
+ if (lastGridTaskView != null) {
+ return indexOfChild(lastGridTaskView);
+ }
+
+ // Returns focus task if there are no grid tasks.
+ return indexOfChild(getFocusedTaskView());
}
/**
@@ -5197,11 +5262,11 @@
}
final int taskCount = getTaskViewCount();
+ int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
- float scrollDiff = taskView.getScrollAdjustment(showAsFullscreen, showAsGrid);
+ float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
int pageScroll = newPageScrolls[i] + (int) scrollDiff;
- int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
if ((mIsRtl && pageScroll < lastTaskScroll)
|| (!mIsRtl && pageScroll > lastTaskScroll)) {
pageScroll = lastTaskScroll;
@@ -5225,8 +5290,7 @@
int childOffset = super.getChildOffset(index);
View child = getChildAt(index);
if (child instanceof TaskView) {
- childOffset += ((TaskView) child).getOffsetAdjustment(showAsFullscreen(),
- showAsGrid());
+ childOffset += ((TaskView) child).getOffsetAdjustment(showAsGrid());
} else if (child instanceof ClearAllButton) {
childOffset += ((ClearAllButton) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
showAsGrid());
@@ -5334,17 +5398,19 @@
int gridTaskSizeAndSpacing = mLastComputedGridTaskSize.width() + mPageSpacing;
int positionDiff = gridTaskSizeAndSpacing * (lastGridTaskViewPosition - taskViewPosition);
- int lastTaskEnd = (mIsRtl
- ? mLastComputedGridSize.left
- : mLastComputedGridSize.right)
- + (mIsRtl ? mPageSpacing : -mPageSpacing);
- int taskEnd = lastTaskEnd + (mIsRtl ? positionDiff : -positionDiff);
+ int taskEnd = getLastTaskEnd() + (mIsRtl ? positionDiff : -positionDiff);
int normalTaskEnd = mIsRtl
? mLastComputedGridTaskSize.left
: mLastComputedGridTaskSize.right;
return taskEnd - normalTaskEnd;
}
+ private int getLastTaskEnd() {
+ return mIsRtl
+ ? mLastComputedGridSize.left + mPageSpacing + mClearAllShortTotalWidthTranslation
+ : mLastComputedGridSize.right - mPageSpacing - mClearAllShortTotalWidthTranslation;
+ }
+
private int getPositionInRow(
TaskView taskView, IntArray topRowIdArray, IntArray bottomRowIdArray) {
int position = topRowIdArray.indexOf(taskView.getTaskViewId());
@@ -5430,6 +5496,9 @@
if (mOverviewSelectEnabled != overviewSelectEnabled) {
mOverviewSelectEnabled = overviewSelectEnabled;
updatePivots();
+ if (!mOverviewSelectEnabled) {
+ setSelectedTask(INVALID_TASK_ID);
+ }
}
}
@@ -5500,7 +5569,9 @@
private void setTaskModalness(float modalness) {
mTaskModalness = modalness;
updatePageOffsets();
- if (getCurrentPageTaskView() != null) {
+ if (mSelectedTask != null) {
+ mSelectedTask.setModalness(modalness);
+ } else if (getCurrentPageTaskView() != null) {
getCurrentPageTaskView().setModalness(modalness);
}
// Only show actions view when it's modal for in-place landscape mode.
@@ -5515,7 +5586,7 @@
}
/** Enables or disables modal state for RecentsView */
- public abstract void setModalStateEnabled(boolean isModalState, boolean animate);
+ public abstract void setModalStateEnabled(int taskId, boolean animate);
public TaskOverlayFactory getTaskOverlayFactory() {
return mTaskOverlayFactory;
@@ -5639,14 +5710,10 @@
taskView = getTaskViewAt(--targetPage);
}
// Target a scroll where targetPage is on left of screen but still fully visible.
- int lastTaskEnd = (mIsRtl
- ? mLastComputedGridSize.left
- : mLastComputedGridSize.right)
- + (mIsRtl ? mPageSpacing : -mPageSpacing);
int normalTaskEnd = mIsRtl
? mLastComputedGridTaskSize.left
: mLastComputedGridTaskSize.right;
- int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - lastTaskEnd;
+ int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - getLastTaskEnd();
// Find a page that is close to targetScroll while not over it.
while (targetPage - 1 >= 0
&& (mIsRtl
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index b0b111d..0d9e412 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -16,8 +16,6 @@
package com.android.quickstep.views;
-import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
-
import android.content.Context;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -27,11 +25,8 @@
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.util.DisplayController;
/**
* A rounded rectangular component containing a single TextView.
@@ -103,36 +98,10 @@
this,
mLauncher.getDeviceProfile(),
getMeasuredHeight(),
- getMeasuredWidth(),
- getThreeButtonNavShift()
+ getMeasuredWidth()
);
}
- // In some cases, when user is using 3-button nav, there isn't enough room for both the
- // 3-button nav and a centered SplitInstructionsView. This function will return an int that will
- // be used to shift the SplitInstructionsView over a bit so that everything looks well-spaced.
- // In many cases, this will return 0, since we don't need to shift it away from the center.
- int getThreeButtonNavShift() {
- DeviceProfile dp = mLauncher.getDeviceProfile();
- if ((DisplayController.getNavigationMode(getContext()) == THREE_BUTTONS)
- && ((dp.isTwoPanels) || (dp.isTablet && !dp.isLandscape))
- // If taskbar is in overview, overview action has dedicated space above nav buttons
- && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
- int navButtonWidth = getResources().getDimensionPixelSize(
- R.dimen.taskbar_nav_buttons_size);
- int extraMargin = getResources().getDimensionPixelSize(
- R.dimen.taskbar_split_instructions_margin);
- // Explanation: The 3-button nav for non-phones sits on one side of the screen, taking
- // up 3 buttons + a side margin worth of space. Our splitInstructionsView starts in the
- // center of the screen and we want to center it in the remaining space, therefore we
- // want to shift it over by half the 3-button layout's width.
- // If the user is using an RtL layout, we shift it the opposite way.
- return -((3 * navButtonWidth + extraMargin) / 2) * (isLayoutRtl() ? -1 : 1);
- } else {
- return 0;
- }
- }
-
public AppCompatTextView getTextView() {
return mTextView;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index 0da70a9..428bd95 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -75,6 +75,7 @@
clipToOutline = true
shouldScaleArrow = true
+ mIsArrowRotated = true
// This synchronizes the arrow and menu to open at the same time
OPEN_CHILD_FADE_START_DELAY = OPEN_FADE_START_DELAY
OPEN_CHILD_FADE_DURATION = OPEN_FADE_DURATION
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index c71a74e..432eadc 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -342,10 +342,11 @@
// Draw splash above thumbnail to hide inconsistencies in rotation and aspect ratios.
if (shouldShowSplashView()) {
+ // Always draw background for hiding inconsistencies, even if splash view is not yet
+ // loaded (which can happen as task icons are loaded asynchronously in the background)
+ canvas.drawRoundRect(x, y, width + 1, height + 1, cornerRadius,
+ cornerRadius, mSplashBackgroundPaint);
if (mSplashView != null) {
- canvas.drawRoundRect(x, y, width + 1, height + 1, cornerRadius,
- cornerRadius, mSplashBackgroundPaint);
-
mSplashView.layout((int) x, (int) (y + 1), (int) width, (int) height - 1);
mSplashView.draw(canvas);
}
@@ -375,6 +376,13 @@
|| isThumbnailRotationDifferentFromTask();
}
+ protected void refreshSplashView() {
+ if (mTask != null) {
+ updateSplashView(mTask.icon);
+ invalidate();
+ }
+ }
+
private void updateSplashView(Drawable icon) {
if (icon == null || icon.getConstantState() == null) {
mSplashViewDrawable = null;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 19ffa27..ab72f2d 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -31,6 +31,7 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
+import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -42,6 +43,7 @@
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -94,6 +96,7 @@
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.util.BorderAnimator;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitSelectStateController;
@@ -372,7 +375,6 @@
// Used when in SplitScreenSelectState
private float mSplitSelectTranslationY;
private float mSplitSelectTranslationX;
- private float mSplitSelectScrollOffsetPrimary;
@Nullable
private ObjectAnimator mIconAndDimAnimator;
@@ -405,6 +407,8 @@
private boolean mIsClickableAsLiveTile = true;
+ @Nullable private final BorderAnimator mBorderAnimator;
+
public TaskView(Context context) {
this(context, null);
}
@@ -414,12 +418,49 @@
}
public TaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public TaskView(
+ Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
mActivity = StatefulActivity.fromContext(context);
setOnClickListener(this::onClick);
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
+
+ boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+ || DesktopTaskView.DESKTOP_MODE_SUPPORTED;
+
+ setWillNotDraw(!keyboardFocusHighlightEnabled);
+
+ mBorderAnimator = !keyboardFocusHighlightEnabled
+ ? null
+ : new BorderAnimator(
+ /* borderBoundsBuilder= */ this::updateBorderBounds,
+ /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width),
+ /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
+ /* borderColor= */ attrs == null
+ ? DEFAULT_BORDER_COLOR
+ : context.getTheme()
+ .obtainStyledAttributes(
+ attrs,
+ R.styleable.TaskView,
+ defStyleAttr,
+ defStyleRes)
+ .getColor(
+ R.styleable.TaskView_borderColor,
+ DEFAULT_BORDER_COLOR),
+ /* invalidateViewCallback= */ TaskView.this::invalidate);
+ }
+
+ protected void updateBorderBounds(Rect bounds) {
+ bounds.set(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
+ mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
+ mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
+ mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()));
}
public void setTaskViewId(int id) {
@@ -463,6 +504,22 @@
mIconTouchDelegate = new TransformingTouchDelegate(mIconView);
}
+ @Override
+ protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ if (mBorderAnimator != null) {
+ mBorderAnimator.buildAnimator(gainFocus).start();
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (mBorderAnimator != null) {
+ mBorderAnimator.drawBorder(canvas);
+ }
+ }
+
/**
* Whether the taskview should take the touch event from parent. Events passed to children
* that might require special handling.
@@ -996,6 +1053,11 @@
}
public void setOrientationState(RecentsOrientedState orientationState) {
+ setIconOrientation(orientationState);
+ setThumbnailOrientation(orientationState);
+ }
+
+ protected void setIconOrientation(RecentsOrientedState orientationState) {
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
@@ -1016,6 +1078,11 @@
int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
: deviceProfile.overviewTaskIconDrawableSizePx;
mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
+ }
+
+ protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
@@ -1215,6 +1282,10 @@
mSnapshotView.setSplashAlpha(mTaskThumbnailSplashAlpha);
}
+ protected void refreshTaskThumbnailSplash() {
+ mSnapshotView.refreshSplashView();
+ }
+
private void setSplitSelectTranslationX(float x) {
mSplitSelectTranslationX = x;
applyTranslationX();
@@ -1225,10 +1296,6 @@
applyTranslationY();
}
- public void setSplitScrollOffsetPrimary(float splitSelectScrollOffsetPrimary) {
- mSplitSelectScrollOffsetPrimary = splitSelectScrollOffsetPrimary;
- }
-
private void setDismissTranslationX(float x) {
mDismissTranslationX = x;
applyTranslationX();
@@ -1292,19 +1359,18 @@
applyTranslationX();
}
- public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+ public float getScrollAdjustment(boolean gridEnabled) {
float scrollAdjustment = 0;
if (gridEnabled) {
scrollAdjustment += mGridTranslationX;
} else {
scrollAdjustment += getPrimaryNonGridTranslationProperty().get(this);
}
- scrollAdjustment += mSplitSelectScrollOffsetPrimary;
return scrollAdjustment;
}
- public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
- return getScrollAdjustment(fullscreenEnabled, gridEnabled);
+ public float getOffsetAdjustment(boolean gridEnabled) {
+ return getScrollAdjustment(gridEnabled);
}
public float getSizeAdjustment(boolean fullscreenEnabled) {
@@ -1373,6 +1439,11 @@
TASK_OFFSET_TRANSLATION_X, TASK_OFFSET_TRANSLATION_Y);
}
+ public FloatProperty<TaskView> getSecondaryTaskOffsetTranslationProperty() {
+ return getPagedOrientationHandler().getSecondaryValue(
+ TASK_OFFSET_TRANSLATION_X, TASK_OFFSET_TRANSLATION_Y);
+ }
+
public FloatProperty<TaskView> getTaskResistanceTranslationProperty() {
return getPagedOrientationHandler().getSecondaryValue(
TASK_RESISTANCE_TRANSLATION_X, TASK_RESISTANCE_TRANSLATION_Y);
@@ -1548,7 +1619,12 @@
int boxWidth;
int boxHeight;
boolean isFocusedTask = isFocusedTask();
- if (isFocusedTask || isDesktopTask()) {
+ if (isDesktopTask()) {
+ Rect lastComputedDesktopTaskSize =
+ getRecentsView().getLastComputedDesktopTaskSize();
+ boxWidth = lastComputedDesktopTaskSize.width();
+ boxHeight = lastComputedDesktopTaskSize.height();
+ } else if (isFocusedTask) {
// Task will be focused and should use focused task size. Use focusTaskRatio
// that is associated with the original orientation of the focused task.
boxWidth = taskWidth;
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt
new file mode 100644
index 0000000..8c13fe3
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.launcher3.taskbar
+
+import androidx.test.runner.AndroidJUnit4
+import com.android.launcher3.statemanager.StateManager
+import com.android.quickstep.RecentsActivity
+import com.android.quickstep.fallback.RecentsState
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidJUnit4::class)
+class FallbackTaskbarUIControllerTest : TaskbarBaseTestCase() {
+
+ lateinit var fallbackTaskbarUIController: FallbackTaskbarUIController
+ lateinit var stateListener: StateManager.StateListener<RecentsState>
+
+ @Mock lateinit var recentsActivity: RecentsActivity
+ @Mock lateinit var stateManager: StateManager<RecentsState>
+
+ @Before
+ override fun setup() {
+ super.setup()
+ whenever(recentsActivity.stateManager).thenReturn(stateManager)
+ fallbackTaskbarUIController = FallbackTaskbarUIController(recentsActivity)
+
+ // Capture registered state listener to send events to in our tests
+ val captor = ArgumentCaptor.forClass(StateManager.StateListener::class.java)
+ fallbackTaskbarUIController.init(taskbarControllers)
+ verify(stateManager).addStateListener(captor.capture())
+ stateListener = captor.value as StateManager.StateListener<RecentsState>
+ }
+
+ @Test
+ fun stateTransitionComplete_stateDefault() {
+ stateListener.onStateTransitionComplete(RecentsState.DEFAULT)
+ // verify dragging disabled
+ verify(taskbarDragController, times(1)).setDisallowGlobalDrag(true)
+ verify(taskbarAllAppsController, times(1)).setDisallowGlobalDrag(true)
+ // verify long click enabled
+ verify(taskbarDragController, times(1)).setDisallowLongClick(false)
+ verify(taskbarAllAppsController, times(1)).setDisallowLongClick(false)
+ // verify split selection enabled
+ verify(taskbarPopupController, times(1)).setAllowInitialSplitSelection(true)
+ }
+
+ @Test
+ fun stateTransitionComplete_stateSplitSelect() {
+ stateListener.onStateTransitionComplete(RecentsState.OVERVIEW_SPLIT_SELECT)
+ // verify dragging disabled
+ verify(taskbarDragController, times(1)).setDisallowGlobalDrag(false)
+ verify(taskbarAllAppsController, times(1)).setDisallowGlobalDrag(false)
+ // verify long click enabled
+ verify(taskbarDragController, times(1)).setDisallowLongClick(true)
+ verify(taskbarAllAppsController, times(1)).setDisallowLongClick(true)
+ // verify split selection enabled
+ verify(taskbarPopupController, times(1)).setAllowInitialSplitSelection(false)
+ }
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 8a78d8c..4cca24e 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -52,8 +52,9 @@
@Mock lateinit var taskbarTranslationController: TaskbarTranslationController
@Mock lateinit var taskbarOverlayController: TaskbarOverlayController
@Mock lateinit var taskbarEduTooltipController: TaskbarEduTooltipController
+ @Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
- lateinit var mTaskbarControllers: TaskbarControllers
+ lateinit var taskbarControllers: TaskbarControllers
@Before
open fun setup() {
@@ -65,7 +66,7 @@
* includes that method to allow mocking it.
*/
MockitoAnnotations.initMocks(this)
- mTaskbarControllers =
+ taskbarControllers =
TaskbarControllers(
taskbarActivityContext,
taskbarDragController,
@@ -90,6 +91,7 @@
taskbarTranslationController,
taskbarRecentAppsController,
taskbarEduTooltipController,
+ keyboardQuickSwitchController
)
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
index 9afd893..bc1b87d 100644
--- a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
@@ -19,7 +19,7 @@
import android.graphics.RectF
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.launcher3.DeviceProfileBaseTest
+import com.android.launcher3.FakeInvariantDeviceProfileTest
import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
import com.android.quickstep.views.TaskView.FullscreenDrawParams
@@ -36,7 +36,7 @@
/** Test for FullscreenDrawParams class. */
@SmallTest
@RunWith(AndroidJUnit4::class)
-class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
+class FullscreenDrawParamsTest : FakeInvariantDeviceProfileTest() {
private val TASK_SCALE = 0.7f
private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java)
diff --git a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
index adbca32..a347156 100644
--- a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
@@ -18,7 +18,7 @@
import android.graphics.Rect
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.launcher3.DeviceProfileBaseTest
+import com.android.launcher3.FakeInvariantDeviceProfileTest
import com.android.launcher3.util.WindowBounds
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -26,7 +26,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
+class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() {
/**
* This is a case when after setting the hotseat, the space needs to be recalculated but it
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9f34775..bc5fa19 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -191,7 +191,7 @@
mLauncher.goHome().switchToOverview().getCurrentTask()
.tapMenu()
.tapSplitMenuItem()
- .getTestActivityTask(2)
+ .getCurrentTask()
.open();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index aed26d3..735c5e6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -92,6 +92,7 @@
@TaskbarModeSwitch(mode = TRANSIENT)
public void testTransientLaunchApp() throws Exception {
getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().assertTaskbarHidden();
}
@Test
@@ -140,6 +141,7 @@
public void testTransientLaunchAppInSplitscreen() throws Exception {
getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen(
TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().assertTaskbarHidden();
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
new file mode 100644
index 0000000..512df8e
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -0,0 +1,405 @@
+/*
+ * 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.quickstep.util
+
+import android.app.ActivityManager
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.graphics.Rect
+import android.os.Handler
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.LauncherState
+import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.statehandlers.DepthController
+import com.android.launcher3.statemanager.StateManager
+import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.withArgCaptor
+import com.android.quickstep.RecentsModel
+import com.android.quickstep.SystemUiProxy
+import com.android.systemui.shared.recents.model.Task
+import java.util.ArrayList
+import java.util.function.Consumer
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidJUnit4::class)
+class SplitSelectStateControllerTest {
+
+ @Mock lateinit var systemUiProxy: SystemUiProxy
+ @Mock lateinit var depthController: DepthController
+ @Mock lateinit var statsLogManager: StatsLogManager
+ @Mock lateinit var stateManager: StateManager<LauncherState>
+ @Mock lateinit var handler: Handler
+ @Mock lateinit var context: Context
+ @Mock lateinit var recentsModel: RecentsModel
+
+ lateinit var splitSelectStateController: SplitSelectStateController
+
+ private val primaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId)
+ private val nonPrimaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId + 10)
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ splitSelectStateController =
+ SplitSelectStateController(
+ context,
+ handler,
+ stateManager,
+ depthController,
+ statsLogManager,
+ systemUiProxy,
+ recentsModel
+ )
+ }
+
+ @Test
+ fun activeTasks_noMatchingTasks() {
+ val nonMatchingComponent = ComponentKey(ComponentName("no", "match"), primaryUserHandle)
+ val groupTask1 =
+ generateGroupTask(
+ ComponentName("pomegranate", "juice"),
+ ComponentName("pumpkin", "pie")
+ )
+ val groupTask2 =
+ generateGroupTask(
+ ComponentName("hotdog", "juice"),
+ ComponentName("personal", "computer")
+ )
+ val tasks: ArrayList<GroupTask> = ArrayList()
+ tasks.add(groupTask1)
+ tasks.add(groupTask2)
+
+ // Assertions happen in the callback we get from what we pass into
+ // #findLastActiveTaskAndRunCallback
+ val taskConsumer =
+ Consumer<Task> { assertNull("No tasks should have matched", it /*task*/) }
+
+ // Capture callback from recentsModel#getTasks()
+ val consumer =
+ withArgCaptor<Consumer<ArrayList<GroupTask>>> {
+ splitSelectStateController.findLastActiveTaskAndRunCallback(
+ nonMatchingComponent,
+ taskConsumer
+ )
+ verify(recentsModel).getTasks(capture())
+ }
+
+ // Send our mocked tasks
+ consumer.accept(tasks)
+ }
+
+ @Test
+ fun activeTasks_singleMatchingTask() {
+ val matchingPackage = "hotdog"
+ val matchingClass = "juice"
+ val matchingComponent =
+ ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
+ val groupTask1 =
+ generateGroupTask(
+ ComponentName(matchingPackage, matchingClass),
+ ComponentName("pomegranate", "juice")
+ )
+ val groupTask2 =
+ generateGroupTask(
+ ComponentName("pumpkin", "pie"),
+ ComponentName("personal", "computer")
+ )
+ val tasks: ArrayList<GroupTask> = ArrayList()
+ tasks.add(groupTask1)
+ tasks.add(groupTask2)
+
+ // Assertions happen in the callback we get from what we pass into
+ // #findLastActiveTaskAndRunCallback
+ val taskConsumer =
+ Consumer<Task> {
+ assertEquals(
+ "ComponentName package mismatched",
+ it.key.baseIntent.component.packageName,
+ matchingPackage
+ )
+ assertEquals(
+ "ComponentName class mismatched",
+ it.key.baseIntent.component.className,
+ matchingClass
+ )
+ assertEquals(it, groupTask1.task1)
+ }
+
+ // Capture callback from recentsModel#getTasks()
+ val consumer =
+ withArgCaptor<Consumer<ArrayList<GroupTask>>> {
+ splitSelectStateController.findLastActiveTaskAndRunCallback(
+ matchingComponent,
+ taskConsumer
+ )
+ verify(recentsModel).getTasks(capture())
+ }
+
+ // Send our mocked tasks
+ consumer.accept(tasks)
+ }
+
+ @Test
+ fun activeTasks_skipTaskWithDifferentUser() {
+ val matchingPackage = "hotdog"
+ val matchingClass = "juice"
+ val nonPrimaryUserComponent =
+ ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
+ val groupTask1 =
+ generateGroupTask(
+ ComponentName(matchingPackage, matchingClass),
+ ComponentName("pomegranate", "juice")
+ )
+ val groupTask2 =
+ generateGroupTask(
+ ComponentName("pumpkin", "pie"),
+ ComponentName("personal", "computer")
+ )
+ val tasks: ArrayList<GroupTask> = ArrayList()
+ tasks.add(groupTask1)
+ tasks.add(groupTask2)
+
+ // Assertions happen in the callback we get from what we pass into
+ // #findLastActiveTaskAndRunCallback
+ val taskConsumer =
+ Consumer<Task> { assertNull("No tasks should have matched", it /*task*/) }
+
+ // Capture callback from recentsModel#getTasks()
+ val consumer =
+ withArgCaptor<Consumer<ArrayList<GroupTask>>> {
+ splitSelectStateController.findLastActiveTaskAndRunCallback(
+ nonPrimaryUserComponent,
+ taskConsumer
+ )
+ verify(recentsModel).getTasks(capture())
+ }
+
+ // Send our mocked tasks
+ consumer.accept(tasks)
+ }
+
+ @Test
+ fun activeTasks_findTaskAsNonPrimaryUser() {
+ val matchingPackage = "hotdog"
+ val matchingClass = "juice"
+ val nonPrimaryUserComponent =
+ ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
+ val groupTask1 =
+ generateGroupTask(
+ ComponentName(matchingPackage, matchingClass),
+ nonPrimaryUserHandle,
+ ComponentName("pomegranate", "juice"),
+ nonPrimaryUserHandle
+ )
+ val groupTask2 =
+ generateGroupTask(
+ ComponentName("pumpkin", "pie"),
+ ComponentName("personal", "computer")
+ )
+ val tasks: ArrayList<GroupTask> = ArrayList()
+ tasks.add(groupTask1)
+ tasks.add(groupTask2)
+
+ // Assertions happen in the callback we get from what we pass into
+ // #findLastActiveTaskAndRunCallback
+ val taskConsumer =
+ Consumer<Task> {
+ assertEquals(
+ "ComponentName package mismatched",
+ it.key.baseIntent.component.packageName,
+ matchingPackage
+ )
+ assertEquals(
+ "ComponentName class mismatched",
+ it.key.baseIntent.component.className,
+ matchingClass
+ )
+ assertEquals("userId mismatched", it.key.userId, nonPrimaryUserHandle.identifier)
+ assertEquals(it, groupTask1.task1)
+ }
+
+ // Capture callback from recentsModel#getTasks()
+ val consumer =
+ withArgCaptor<Consumer<ArrayList<GroupTask>>> {
+ splitSelectStateController.findLastActiveTaskAndRunCallback(
+ nonPrimaryUserComponent,
+ taskConsumer
+ )
+ verify(recentsModel).getTasks(capture())
+ }
+
+ // Send our mocked tasks
+ consumer.accept(tasks)
+ }
+
+ @Test
+ fun activeTasks_multipleMatchMostRecentTask() {
+ val matchingPackage = "hotdog"
+ val matchingClass = "juice"
+ val matchingComponent =
+ ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
+ val groupTask1 =
+ generateGroupTask(
+ ComponentName(matchingPackage, matchingClass),
+ ComponentName("pumpkin", "pie")
+ )
+ val groupTask2 =
+ generateGroupTask(
+ ComponentName("pomegranate", "juice"),
+ ComponentName(matchingPackage, matchingClass)
+ )
+ val tasks: ArrayList<GroupTask> = ArrayList()
+ tasks.add(groupTask2)
+ tasks.add(groupTask1)
+
+ // Assertions happen in the callback we get from what we pass into
+ // #findLastActiveTaskAndRunCallback
+ val taskConsumer =
+ Consumer<Task> {
+ assertEquals(
+ "ComponentName package mismatched",
+ it.key.baseIntent.component.packageName,
+ matchingPackage
+ )
+ assertEquals(
+ "ComponentName class mismatched",
+ it.key.baseIntent.component.className,
+ matchingClass
+ )
+ assertEquals(it, groupTask2.task2)
+ }
+
+ // Capture callback from recentsModel#getTasks()
+ val consumer =
+ withArgCaptor<Consumer<ArrayList<GroupTask>>> {
+ splitSelectStateController.findLastActiveTaskAndRunCallback(
+ matchingComponent,
+ taskConsumer
+ )
+ verify(recentsModel).getTasks(capture())
+ }
+
+ // Send our mocked tasks
+ consumer.accept(tasks)
+ }
+
+ @Test
+ fun setInitialApp_withTaskId() {
+ splitSelectStateController.setInitialTaskSelect(
+ null /*intent*/,
+ -1 /*stagePosition*/,
+ ItemInfo(),
+ null /*splitEvent*/,
+ 10 /*alreadyRunningTask*/
+ )
+ assertTrue(splitSelectStateController.isSplitSelectActive)
+ }
+
+ @Test
+ fun setInitialApp_withIntent() {
+ splitSelectStateController.setInitialTaskSelect(
+ Intent() /*intent*/,
+ -1 /*stagePosition*/,
+ ItemInfo(),
+ null /*splitEvent*/,
+ -1 /*alreadyRunningTask*/
+ )
+ assertTrue(splitSelectStateController.isSplitSelectActive)
+ }
+
+ @Test
+ fun resetAfterInitial() {
+ splitSelectStateController.setInitialTaskSelect(
+ Intent() /*intent*/,
+ -1 /*stagePosition*/,
+ ItemInfo(),
+ null /*splitEvent*/,
+ -1
+ )
+ splitSelectStateController.resetState()
+ assertFalse(splitSelectStateController.isSplitSelectActive)
+ }
+
+ // Generate GroupTask with default userId.
+ private fun generateGroupTask(
+ task1ComponentName: ComponentName,
+ task2ComponentName: ComponentName
+ ): GroupTask {
+ val task1 = Task()
+ var taskInfo = ActivityManager.RunningTaskInfo()
+ var intent = Intent()
+ intent.component = task1ComponentName
+ taskInfo.baseIntent = intent
+ task1.key = Task.TaskKey(taskInfo)
+
+ val task2 = Task()
+ taskInfo = ActivityManager.RunningTaskInfo()
+ intent = Intent()
+ intent.component = task2ComponentName
+ taskInfo.baseIntent = intent
+ task2.key = Task.TaskKey(taskInfo)
+ return GroupTask(
+ task1,
+ task2,
+ SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1)
+ )
+ }
+
+ // Generate GroupTask with custom user handles.
+ private fun generateGroupTask(
+ task1ComponentName: ComponentName,
+ userHandle1: UserHandle,
+ task2ComponentName: ComponentName,
+ userHandle2: UserHandle
+ ): GroupTask {
+ val task1 = Task()
+ var taskInfo = ActivityManager.RunningTaskInfo()
+ // Apply custom userHandle1
+ taskInfo.userId = userHandle1.identifier
+ var intent = Intent()
+ intent.component = task1ComponentName
+ taskInfo.baseIntent = intent
+ task1.key = Task.TaskKey(taskInfo)
+ val task2 = Task()
+ taskInfo = ActivityManager.RunningTaskInfo()
+ // Apply custom userHandle2
+ taskInfo.userId = userHandle2.identifier
+ intent = Intent()
+ intent.component = task2ComponentName
+ taskInfo.baseIntent = intent
+ task2.key = Task.TaskKey(taskInfo)
+ return GroupTask(
+ task1,
+ task2,
+ SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1)
+ )
+ }
+}
diff --git a/res/color/app_subtitle_text_dark.xml b/res/color/app_subtitle_text_dark.xml
new file mode 100644
index 0000000..220d10f
--- /dev/null
+++ b/res/color/app_subtitle_text_dark.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#EFF1F2" android:state_expanded="false" />
+ <item android:color="#191C1D" android:state_expanded="true" />
+</selector>
diff --git a/res/color/app_subtitle_text_light.xml b/res/color/app_subtitle_text_light.xml
new file mode 100644
index 0000000..fb00baa
--- /dev/null
+++ b/res/color/app_subtitle_text_light.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/textColorSecondary"/>
+</selector>
diff --git a/res/color/app_title_text_dark.xml b/res/color/app_title_text_dark.xml
new file mode 100644
index 0000000..220d10f
--- /dev/null
+++ b/res/color/app_title_text_dark.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#EFF1F2" android:state_expanded="false" />
+ <item android:color="#191C1D" android:state_expanded="true" />
+</selector>
diff --git a/res/color/app_title_text_light.xml b/res/color/app_title_text_light.xml
new file mode 100644
index 0000000..bb52973
--- /dev/null
+++ b/res/color/app_title_text_light.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/textColorPrimary"/>
+</selector>
diff --git a/res/drawable-sw600dp/ic_transient_taskbar_all_apps_button.xml b/res/drawable-sw600dp/ic_transient_taskbar_all_apps_button.xml
new file mode 100644
index 0000000..6e740ae
--- /dev/null
+++ b/res/drawable-sw600dp/ic_transient_taskbar_all_apps_button.xml
@@ -0,0 +1,48 @@
+<?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="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <path
+ android:pathData="M13.5,17C12.538,17 11.715,16.65 11.033,15.967C10.35,15.285 10,14.462 10,13.5C10,12.538 10.35,11.715 11.033,11.033C11.715,10.35 12.538,10 13.5,10C14.462,10 15.285,10.35 15.967,11.033C16.65,11.715 17,12.538 17,13.5C17,14.462 16.65,15.285 15.967,15.967C15.285,16.65 14.462,17 13.5,17Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M24,17C23.038,17 22.215,16.65 21.532,15.967C20.85,15.285 20.5,14.462 20.5,13.5C20.5,12.538 20.85,11.715 21.532,11.033C22.215,10.35 23.038,10 24,10C24.962,10 25.785,10.35 26.468,11.033C27.15,11.715 27.5,12.538 27.5,13.5C27.5,14.462 27.15,15.285 26.468,15.967C25.785,16.65 24.962,17 24,17Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M34.5,17C33.537,17 32.715,16.65 32.033,15.967C31.35,15.285 31,14.462 31,13.5C31,12.538 31.35,11.715 32.033,11.033C32.715,10.35 33.537,10 34.5,10C35.463,10 36.285,10.35 36.967,11.033C37.65,11.715 38,12.538 38,13.5C38,14.462 37.65,15.285 36.967,15.967C36.285,16.65 35.463,17 34.5,17Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M13.5,27.5C12.538,27.5 11.715,27.15 11.033,26.468C10.35,25.785 10,24.962 10,24C10,23.038 10.35,22.215 11.033,21.532C11.715,20.85 12.538,20.5 13.5,20.5C14.462,20.5 15.285,20.85 15.967,21.532C16.65,22.215 17,23.038 17,24C17,24.962 16.65,25.785 15.967,26.468C15.285,27.15 14.462,27.5 13.5,27.5Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M24,27.5C23.038,27.5 22.215,27.15 21.532,26.468C20.85,25.785 20.5,24.962 20.5,24C20.5,23.038 20.85,22.215 21.532,21.532C22.215,20.85 23.038,20.5 24,20.5C24.962,20.5 25.785,20.85 26.468,21.532C27.15,22.215 27.5,23.038 27.5,24C27.5,24.962 27.15,25.785 26.468,26.468C25.785,27.15 24.962,27.5 24,27.5Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M34.5,27.5C33.537,27.5 32.715,27.15 32.033,26.468C31.35,25.785 31,24.962 31,24C31,23.038 31.35,22.215 32.033,21.532C32.715,20.85 33.537,20.5 34.5,20.5C35.463,20.5 36.285,20.85 36.967,21.532C37.65,22.215 38,23.038 38,24C38,24.962 37.65,25.785 36.967,26.468C36.285,27.15 35.463,27.5 34.5,27.5Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M13.5,38C12.538,38 11.715,37.65 11.033,36.967C10.35,36.285 10,35.463 10,34.5C10,33.537 10.35,32.715 11.033,32.033C11.715,31.35 12.538,31 13.5,31C14.462,31 15.285,31.35 15.967,32.033C16.65,32.715 17,33.537 17,34.5C17,35.463 16.65,36.285 15.967,36.967C15.285,37.65 14.462,38 13.5,38Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M24,38C23.038,38 22.215,37.65 21.532,36.967C20.85,36.285 20.5,35.463 20.5,34.5C20.5,33.537 20.85,32.715 21.532,32.033C22.215,31.35 23.038,31 24,31C24.962,31 25.785,31.35 26.468,32.033C27.15,32.715 27.5,33.537 27.5,34.5C27.5,35.463 27.15,36.285 26.468,36.967C25.785,37.65 24.962,38 24,38Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M34.5,38C33.537,38 32.715,37.65 32.033,36.967C31.35,36.285 31,35.463 31,34.5C31,33.537 31.35,32.715 32.033,32.033C32.715,31.35 33.537,31 34.5,31C35.463,31 36.285,31.35 36.967,32.033C37.65,32.715 38,33.537 38,34.5C38,35.463 37.65,36.285 36.967,36.967C36.285,37.65 35.463,38 34.5,38Z"
+ android:fillColor="#40484B"/>
+</vector>
diff --git a/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml b/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml
new file mode 100644
index 0000000..47f2a5d
--- /dev/null
+++ b/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml
@@ -0,0 +1,48 @@
+<?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="52dp"
+ android:height="52dp"
+ android:viewportWidth="52"
+ android:viewportHeight="52">
+ <path
+ android:pathData="M15.5,19C14.538,19 13.715,18.65 13.033,17.968C12.35,17.285 12,16.462 12,15.5C12,14.538 12.35,13.715 13.033,13.033C13.715,12.35 14.538,12 15.5,12C16.462,12 17.285,12.35 17.968,13.033C18.65,13.715 19,14.538 19,15.5C19,16.462 18.65,17.285 17.968,17.968C17.285,18.65 16.462,19 15.5,19Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M26,19C25.038,19 24.215,18.65 23.532,17.968C22.85,17.285 22.5,16.462 22.5,15.5C22.5,14.538 22.85,13.715 23.532,13.033C24.215,12.35 25.038,12 26,12C26.962,12 27.785,12.35 28.468,13.033C29.15,13.715 29.5,14.538 29.5,15.5C29.5,16.462 29.15,17.285 28.468,17.968C27.785,18.65 26.962,19 26,19Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M36.5,19C35.537,19 34.715,18.65 34.033,17.968C33.35,17.285 33,16.462 33,15.5C33,14.538 33.35,13.715 34.033,13.033C34.715,12.35 35.537,12 36.5,12C37.463,12 38.285,12.35 38.967,13.033C39.65,13.715 40,14.538 40,15.5C40,16.462 39.65,17.285 38.967,17.968C38.285,18.65 37.463,19 36.5,19Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M15.5,29.5C14.538,29.5 13.715,29.15 13.033,28.468C12.35,27.785 12,26.962 12,26C12,25.038 12.35,24.215 13.033,23.532C13.715,22.85 14.538,22.5 15.5,22.5C16.462,22.5 17.285,22.85 17.968,23.532C18.65,24.215 19,25.038 19,26C19,26.962 18.65,27.785 17.968,28.468C17.285,29.15 16.462,29.5 15.5,29.5Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M26,29.5C25.038,29.5 24.215,29.15 23.532,28.468C22.85,27.785 22.5,26.962 22.5,26C22.5,25.038 22.85,24.215 23.532,23.532C24.215,22.85 25.038,22.5 26,22.5C26.962,22.5 27.785,22.85 28.468,23.532C29.15,24.215 29.5,25.038 29.5,26C29.5,26.962 29.15,27.785 28.468,28.468C27.785,29.15 26.962,29.5 26,29.5Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M36.5,29.5C35.537,29.5 34.715,29.15 34.033,28.468C33.35,27.785 33,26.962 33,26C33,25.038 33.35,24.215 34.033,23.532C34.715,22.85 35.537,22.5 36.5,22.5C37.463,22.5 38.285,22.85 38.967,23.532C39.65,24.215 40,25.038 40,26C40,26.962 39.65,27.785 38.967,28.468C38.285,29.15 37.463,29.5 36.5,29.5Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M15.5,40C14.538,40 13.715,39.65 13.033,38.967C12.35,38.285 12,37.463 12,36.5C12,35.537 12.35,34.715 13.033,34.033C13.715,33.35 14.538,33 15.5,33C16.462,33 17.285,33.35 17.968,34.033C18.65,34.715 19,35.537 19,36.5C19,37.463 18.65,38.285 17.968,38.967C17.285,39.65 16.462,40 15.5,40Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M26,40C25.038,40 24.215,39.65 23.532,38.967C22.85,38.285 22.5,37.463 22.5,36.5C22.5,35.537 22.85,34.715 23.532,34.033C24.215,33.35 25.038,33 26,33C26.962,33 27.785,33.35 28.468,34.033C29.15,34.715 29.5,35.537 29.5,36.5C29.5,37.463 29.15,38.285 28.468,38.967C27.785,39.65 26.962,40 26,40Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M36.5,40C35.537,40 34.715,39.65 34.033,38.967C33.35,38.285 33,37.463 33,36.5C33,35.537 33.35,34.715 34.033,34.033C34.715,33.35 35.537,33 36.5,33C37.463,33 38.285,33.35 38.967,34.033C39.65,34.715 40,35.537 40,36.5C40,37.463 39.65,38.285 38.967,38.967C38.285,39.65 37.463,40 36.5,40Z"
+ android:fillColor="#40484B"/>
+</vector>
diff --git a/res/drawable/bg_widgets_content.xml b/res/drawable/bg_widgets_content.xml
new file mode 100644
index 0000000..b0b699b
--- /dev/null
+++ b/res/drawable/bg_widgets_content.xml
@@ -0,0 +1,61 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!--
+ L -> large radius
+ s -> small radius
+ 0 -> no radius
+ -->
+
+ <!-- SINGLE : L L L L -->
+ <item android:state_single="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners android:radius="@dimen/widget_list_top_bottom_corner_radius"/>
+ </shape>
+ </item>
+
+ <!-- FIRST : 0 0 s s -->
+ <item android:state_first="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:bottomLeftRadius="@dimen/widget_list_content_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_content_corner_radius" />
+ </shape>
+ </item>
+
+ <!-- MIDDLE : 0 0 s s -->
+ <item android:state_middle="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:bottomLeftRadius="@dimen/widget_list_content_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_content_corner_radius" />
+ </shape>
+ </item>
+
+ <!-- LAST : 0 0 L L -->
+ <item android:state_last="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+ </shape>
+ </item>
+</selector>
diff --git a/res/drawable/bg_widgets_header.xml b/res/drawable/bg_widgets_header.xml
new file mode 100644
index 0000000..a89aad4
--- /dev/null
+++ b/res/drawable/bg_widgets_header.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetTop="@dimen/widget_list_entry_spacing" >
+ <ripple
+ android:color="?android:attr/colorControlHighlight"
+ android:paddingTop="@dimen/widget_list_header_view_vertical_padding"
+ android:paddingBottom="@dimen/widget_list_header_view_vertical_padding" >
+ <item android:id="@android:id/mask"
+ android:drawable="@drawable/bg_widgets_header_states" />
+ <item android:drawable="@drawable/bg_widgets_header_states" />
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_header_large_screen.xml b/res/drawable/bg_widgets_header_large_screen.xml
new file mode 100644
index 0000000..e1408cc
--- /dev/null
+++ b/res/drawable/bg_widgets_header_large_screen.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetTop="@dimen/widget_list_entry_spacing" >
+ <ripple
+ android:color="@color/accent_ripple_color"
+ android:paddingTop="@dimen/widget_list_header_view_vertical_padding"
+ android:paddingBottom="@dimen/widget_list_header_view_vertical_padding" >
+ <item android:id="@android:id/mask"
+ android:drawable="@drawable/bg_widgets_header_states_large_screen" />
+ <item android:drawable="@drawable/bg_widgets_header_states_large_screen" />
+ </ripple>
+</inset>
diff --git a/res/drawable/bg_widgets_header_states.xml b/res/drawable/bg_widgets_header_states.xml
new file mode 100644
index 0000000..f45a7ab
--- /dev/null
+++ b/res/drawable/bg_widgets_header_states.xml
@@ -0,0 +1,95 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!--
+ L -> large radius
+ s -> small radius
+ 0 -> no radiuls
+ -->
+
+ <!-- SINGLE : L L L L -->
+ <item android:state_single="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+ </shape>
+ </item>
+
+ <!-- FIRST_EXPANDED : L L 0 0 -->
+ <item android:state_first="true" android:state_expanded="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomLeftRadius="0dp"
+ android:bottomRightRadius="0dp" />
+ </shape>
+ </item>
+
+ <!-- FIRST : L L s s -->
+ <item android:state_first="true" >
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomLeftRadius="@dimen/widget_list_content_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_content_corner_radius" />
+ </shape>
+ </item>
+
+ <!-- MIDDLE_EXPANDED : s s 0 0 -->
+ <item android:state_middle="true" android:state_expanded="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:topLeftRadius="@dimen/widget_list_content_corner_radius"
+ android:topRightRadius="@dimen/widget_list_content_corner_radius"
+ android:bottomLeftRadius="0dp"
+ android:bottomRightRadius="0dp" />
+ </shape>
+ </item>
+
+ <!-- MIDDLE : s s s s -->
+ <item android:state_middle="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:topLeftRadius="@dimen/widget_list_content_corner_radius"
+ android:topRightRadius="@dimen/widget_list_content_corner_radius"
+ android:bottomLeftRadius="@dimen/widget_list_content_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_content_corner_radius" />
+ </shape>
+ </item>
+
+ <!-- LAST : s s L L -->
+ <item android:state_last="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/surface" />
+ <corners
+ android:topLeftRadius="@dimen/widget_list_content_corner_radius"
+ android:topRightRadius="@dimen/widget_list_content_corner_radius"
+ android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+ </shape>
+ </item>
+</selector>
diff --git a/res/drawable/bg_widgets_header_states_large_screen.xml b/res/drawable/bg_widgets_header_states_large_screen.xml
new file mode 100644
index 0000000..1ee5fe5
--- /dev/null
+++ b/res/drawable/bg_widgets_header_states_large_screen.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_expanded="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/widget_picker_background_selected" />
+ <corners android:radius="@dimen/widget_list_top_bottom_corner_radius" />
+ </shape>
+ </item>
+
+ <item android:state_expanded="false">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/transparent" />
+ <corners android:radius="@dimen/widget_list_top_bottom_corner_radius" />
+ </shape>
+ </item>
+</selector>
diff --git a/res/drawable/ic_all_apps_button.xml b/res/drawable/ic_all_apps_button.xml
deleted file mode 100644
index 4f0b6a8..0000000
--- a/res/drawable/ic_all_apps_button.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="29dp"
- android:height="28dp"
- android:viewportWidth="29"
- android:viewportHeight="28">
- <group
- android:pivotY="14.5"
- android:pivotX="22"
- android:scaleX=".50"
- android:scaleY=".50">
- <path
- android:pathData="M4 7C3.0375 7 2.215 6.65 1.5325 5.9675C0.85 5.285 0.5 4.4625 0.5 3.5C0.5 2.5375 0.85 1.715 1.5325 1.0325C2.215 0.35 3.0375 0 4 0C4.9625 0 5.785 0.35 6.4675 1.0325C7.15 1.715 7.5 2.5375 7.5 3.5C7.5 4.4625 7.15 5.285 6.4675 5.9675C5.785 6.65 4.9625 7 4 7Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M14.5 7C13.5375 7 12.715 6.65 12.0325 5.9675C11.35 5.285 11 4.4625 11 3.5C11 2.5375 11.35 1.715 12.0325 1.0325C12.715 0.35 13.5375 0 14.5 0C15.4625 0 16.285 0.35 16.9675 1.0325C17.65 1.715 18 2.5375 18 3.5C18 4.4625 17.65 5.285 16.9675 5.9675C16.285 6.65 15.4625 7 14.5 7Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M25 7C24.0375 7 23.215 6.65 22.5325 5.9675C21.85 5.285 21.5 4.4625 21.5 3.5C21.5 2.5375 21.85 1.715 22.5325 1.0325C23.215 0.35 24.0375 0 25 0C25.9625 0 26.785 0.35 27.4675 1.0325C28.15 1.715 28.5 2.5375 28.5 3.5C28.5 4.4625 28.15 5.285 27.4675 5.9675C26.785 6.65 25.9625 7 25 7Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M4 17.5C3.0375 17.5 2.215 17.15 1.5325 16.4675C0.85 15.785 0.5 14.9625 0.5 14C0.5 13.0375 0.85 12.215 1.5325 11.5325C2.215 10.85 3.0375 10.5 4 10.5C4.9625 10.5 5.785 10.85 6.4675 11.5325C7.15 12.215 7.5 13.0375 7.5 14C7.5 14.9625 7.15 15.785 6.4675 16.4675C5.785 17.15 4.9625 17.5 4 17.5Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M14.5 17.5C13.5375 17.5 12.715 17.15 12.0325 16.4675C11.35 15.785 11 14.9625 11 14C11 13.0375 11.35 12.215 12.0325 11.5325C12.715 10.85 13.5375 10.5 14.5 10.5C15.4625 10.5 16.285 10.85 16.9675 11.5325C17.65 12.215 18 13.0375 18 14C18 14.9625 17.65 15.785 16.9675 16.4675C16.285 17.15 15.4625 17.5 14.5 17.5Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M25 17.5C24.0375 17.5 23.215 17.15 22.5325 16.4675C21.85 15.785 21.5 14.9625 21.5 14C21.5 13.0375 21.85 12.215 22.5325 11.5325C23.215 10.85 24.0375 10.5 25 10.5C25.9625 10.5 26.785 10.85 27.4675 11.5325C28.15 12.215 28.5 13.0375 28.5 14C28.5 14.9625 28.15 15.785 27.4675 16.4675C26.785 17.15 25.9625 17.5 25 17.5Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M4 28C3.0375 28 2.215 27.65 1.5325 26.9675C0.85 26.285 0.5 25.4625 0.5 24.5C0.5 23.5375 0.85 22.715 1.5325 22.0325C2.215 21.35 3.0375 21 4 21C4.9625 21 5.785 21.35 6.4675 22.0325C7.15 22.715 7.5 23.5375 7.5 24.5C7.5 25.4625 7.15 26.285 6.4675 26.9675C5.785 27.65 4.9625 28 4 28Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M14.5 28C13.5375 28 12.715 27.65 12.0325 26.9675C11.35 26.285 11 25.4625 11 24.5C11 23.5375 11.35 22.715 12.0325 22.0325C12.715 21.35 13.5375 21 14.5 21C15.4625 21 16.285 21.35 16.9675 22.0325C17.65 22.715 18 23.5375 18 24.5C18 25.4625 17.65 26.285 16.9675 26.9675C16.285 27.65 15.4625 28 14.5 28Z"
- android:fillColor="@color/all_apps_button_color"/>
- <path
- android:pathData="M25 28C24.0375 28 23.215 27.65 22.5325 26.9675C21.85 26.285 21.5 25.4625 21.5 24.5C21.5 23.5375 21.85 22.715 22.5325 22.0325C23.215 21.35 24.0375 21 25 21C25.9625 21 26.785 21.35 27.4675 22.0325C28.15 22.715 28.5 23.5375 28.5 24.5C28.5 25.4625 28.15 26.285 27.4675 26.9675C26.785 27.65 25.9625 28 25 28Z"
- android:fillColor="@color/all_apps_button_color"/>
- </group>
-</vector>
diff --git a/res/drawable/ic_taskbar_all_apps_button.xml b/res/drawable/ic_taskbar_all_apps_button.xml
new file mode 100644
index 0000000..82fbbea
--- /dev/null
+++ b/res/drawable/ic_taskbar_all_apps_button.xml
@@ -0,0 +1,48 @@
+<?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="44dp"
+ android:height="44dp"
+ android:viewportWidth="44"
+ android:viewportHeight="44">
+ <path
+ android:pathData="M13,16C12.175,16 11.47,15.7 10.885,15.115C10.3,14.53 10,13.825 10,13C10,12.175 10.3,11.47 10.885,10.885C11.47,10.3 12.175,10 13,10C13.825,10 14.53,10.3 15.115,10.885C15.7,11.47 16,12.175 16,13C16,13.825 15.7,14.53 15.115,15.115C14.53,15.7 13.825,16 13,16Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M22,16C21.175,16 20.47,15.7 19.885,15.115C19.3,14.53 19,13.825 19,13C19,12.175 19.3,11.47 19.885,10.885C20.47,10.3 21.175,10 22,10C22.825,10 23.53,10.3 24.115,10.885C24.7,11.47 25,12.175 25,13C25,13.825 24.7,14.53 24.115,15.115C23.53,15.7 22.825,16 22,16Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M31,16C30.175,16 29.47,15.7 28.885,15.115C28.3,14.53 28,13.825 28,13C28,12.175 28.3,11.47 28.885,10.885C29.47,10.3 30.175,10 31,10C31.825,10 32.53,10.3 33.115,10.885C33.7,11.47 34,12.175 34,13C34,13.825 33.7,14.53 33.115,15.115C32.53,15.7 31.825,16 31,16Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M13,25C12.175,25 11.47,24.7 10.885,24.115C10.3,23.53 10,22.825 10,22C10,21.175 10.3,20.47 10.885,19.885C11.47,19.3 12.175,19 13,19C13.825,19 14.53,19.3 15.115,19.885C15.7,20.47 16,21.175 16,22C16,22.825 15.7,23.53 15.115,24.115C14.53,24.7 13.825,25 13,25Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M22,25C21.175,25 20.47,24.7 19.885,24.115C19.3,23.53 19,22.825 19,22C19,21.175 19.3,20.47 19.885,19.885C20.47,19.3 21.175,19 22,19C22.825,19 23.53,19.3 24.115,19.885C24.7,20.47 25,21.175 25,22C25,22.825 24.7,23.53 24.115,24.115C23.53,24.7 22.825,25 22,25Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M31,25C30.175,25 29.47,24.7 28.885,24.115C28.3,23.53 28,22.825 28,22C28,21.175 28.3,20.47 28.885,19.885C29.47,19.3 30.175,19 31,19C31.825,19 32.53,19.3 33.115,19.885C33.7,20.47 34,21.175 34,22C34,22.825 33.7,23.53 33.115,24.115C32.53,24.7 31.825,25 31,25Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M13,34C12.175,34 11.47,33.7 10.885,33.115C10.3,32.53 10,31.825 10,31C10,30.175 10.3,29.47 10.885,28.885C11.47,28.3 12.175,28 13,28C13.825,28 14.53,28.3 15.115,28.885C15.7,29.47 16,30.175 16,31C16,31.825 15.7,32.53 15.115,33.115C14.53,33.7 13.825,34 13,34Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M22,34C21.175,34 20.47,33.7 19.885,33.115C19.3,32.53 19,31.825 19,31C19,30.175 19.3,29.47 19.885,28.885C20.47,28.3 21.175,28 22,28C22.825,28 23.53,28.3 24.115,28.885C24.7,29.47 25,30.175 25,31C25,31.825 24.7,32.53 24.115,33.115C23.53,33.7 22.825,34 22,34Z"
+ android:fillColor="#40484B"/>
+ <path
+ android:pathData="M31,34C30.175,34 29.47,33.7 28.885,33.115C28.3,32.53 28,31.825 28,31C28,30.175 28.3,29.47 28.885,28.885C29.47,28.3 30.175,28 31,28C31.825,28 32.53,28.3 33.115,28.885C33.7,29.47 34,30.175 34,31C34,31.825 33.7,32.53 33.115,33.115C32.53,33.7 31.825,34 31,34Z"
+ android:fillColor="#40484B"/>
+</vector>
diff --git a/res/drawable/popup_background_material_u.xml b/res/drawable/popup_background_material_u.xml
new file mode 100644
index 0000000..4d40ba8
--- /dev/null
+++ b/res/drawable/popup_background_material_u.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?attr/popupColorPrimary"/>
+ <corners android:radius="@dimen/dialogCornerRadius"/>
+</shape>
\ No newline at end of file
diff --git a/res/drawable/widget_suggestions.xml b/res/drawable/widget_suggestions.xml
new file mode 100644
index 0000000..b090a68
--- /dev/null
+++ b/res/drawable/widget_suggestions.xml
@@ -0,0 +1,27 @@
+<!--
+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"
+ android:tint="@color/widget_picker_background_selected"
+ android:gravity="center"
+ >
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.65,13 L11,7.35 16.65,1.7 22.3,7.35ZM3,11V3H11V11ZM13,21V13H21V21ZM3,21V13H11V21ZM5,9H9V5H5ZM16.675,10.2 L19.5,7.375 16.675,4.55 13.85,7.375ZM15,19H19V15H15ZM5,19H9V15H5ZM9,9ZM13.85,7.375ZM9,15ZM15,15Z"/>
+</vector>
diff --git a/res/drawable/widget_suggestions_icon.xml b/res/drawable/widget_suggestions_icon.xml
new file mode 100644
index 0000000..919b5e4
--- /dev/null
+++ b/res/drawable/widget_suggestions_icon.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="oval">
+ <size
+ android:width="48dp"
+ android:height="48dp" />
+ <solid android:color="@color/surface"/>
+ </shape>
+ </item>
+ <item
+ android:width="24dp"
+ android:height="24dp"
+ android:drawable="@drawable/widget_suggestions"
+ android:gravity="center" />
+</layer-list>
diff --git a/res/drawable/widgets_tray_expand_button.xml b/res/drawable/widgets_tray_expand_button.xml
index 8316e0f..f2e142e 100644
--- a/res/drawable/widgets_tray_expand_button.xml
+++ b/res/drawable/widgets_tray_expand_button.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true"
+ <item android:state_expanded="true"
android:drawable="@drawable/ic_expand_less" />
- <item android:state_checked="false"
+ <item android:state_expanded="false"
android:drawable="@drawable/ic_expand_more" />
</selector>
diff --git a/res/layout/deep_shortcut_container.xml b/res/layout/deep_shortcut_container.xml
new file mode 100644
index 0000000..b6c3f56
--- /dev/null
+++ b/res/layout/deep_shortcut_container.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/deep_shortcuts_container"
+ android:background="@drawable/popup_background_material_u"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tag="@string/popup_container_iterate_children"
+ android:elevation="@dimen/deep_shortcuts_elevation"
+ android:orientation="vertical"/>
\ No newline at end of file
diff --git a/res/layout/deep_shortcut_material_u.xml b/res/layout/deep_shortcut_material_u.xml
new file mode 100644
index 0000000..fc019e9
--- /dev/null
+++ b/res/layout/deep_shortcut_material_u.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+<com.android.launcher3.shortcuts.DeepShortcutView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/deep_shortcut_material"
+ android:layout_width="@dimen/bg_popup_item_width"
+ android:layout_height="@dimen/bg_popup_item_height"
+ android:elevation="@dimen/deep_shortcuts_elevation"
+ android:background="@drawable/middle_item_primary"
+ android:theme="@style/PopupItem" >
+
+ <com.android.launcher3.shortcuts.DeepShortcutTextView
+ style="@style/BaseIcon"
+ android:id="@+id/bubble_text"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="start|center_vertical"
+ android:textAlignment="viewStart"
+ android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
+ android:paddingEnd="@dimen/popup_padding_end"
+ android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorPrimary"
+ launcher:layoutHorizontal="true"
+ launcher:iconDisplay="shortcut_popup"
+ launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" />
+
+ <View
+ android:id="@+id/icon"
+ android:layout_width="@dimen/deep_shortcut_icon_size"
+ android:layout_height="@dimen/deep_shortcut_icon_size"
+ android:layout_marginStart="@dimen/popup_padding_start"
+ android:layout_gravity="start|center_vertical"
+ android:background="@drawable/ic_deepshortcut_placeholder"/>
+</com.android.launcher3.shortcuts.DeepShortcutView>
\ No newline at end of file
diff --git a/res/layout/home_settings.xml b/res/layout/home_settings.xml
index 0f2461a..c0f16e2 100644
--- a/res/layout/home_settings.xml
+++ b/res/layout/home_settings.xml
@@ -12,6 +12,9 @@
android:layout_marginHorizontal="@dimen/developer_options_filter_margins"
android:hint="@string/developer_options_filter_hint"
android:visibility="gone"
+ android:inputType="text"
+ android:maxLines="1"
+ android:imeOptions="actionDone"
/>
<FrameLayout
diff --git a/res/layout/popup_container_material_u.xml b/res/layout/popup_container_material_u.xml
new file mode 100644
index 0000000..d3036b6
--- /dev/null
+++ b/res/layout/popup_container_material_u.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<com.android.launcher3.popup.PopupContainerWithArrow
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/popup_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
\ No newline at end of file
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 21d532e..cbd7fa4 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -18,6 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/bg_popup_item_width"
android:layout_height="wrap_content"
+ android:id="@+id/system_shortcut"
android:minHeight="@dimen/bg_popup_item_height"
android:elevation="@dimen/deep_shortcuts_elevation"
android:background="@drawable/middle_item_primary"
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons_container.xml
similarity index 89%
rename from res/layout/system_shortcut_icons.xml
rename to res/layout/system_shortcut_icons_container.xml
index 775a45f..ee104d9 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/system_shortcut_icons_container.xml
@@ -26,7 +26,7 @@
android:clipToPadding="true">
<Space android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:id="@+id/separator"/>
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:id="@+id/separator"/>
</LinearLayout>
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons_container_material_u.xml
similarity index 73%
copy from res/layout/system_shortcut_icons.xml
copy to res/layout/system_shortcut_icons_container_material_u.xml
index 775a45f..afd11e6 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/system_shortcut_icons_container_material_u.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- 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.
@@ -17,16 +17,16 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/system_shortcut_icons"
+ android:tag="@string/popup_container_iterate_children"
android:layout_width="match_parent"
android:layout_height="@dimen/system_shortcut_header_height"
android:orientation="horizontal"
android:gravity="end|center_vertical"
- android:background="@drawable/single_item_primary"
- android:elevation="@dimen/deep_shortcuts_elevation"
- android:clipToPadding="true">
+ android:background="@drawable/popup_background_material_u"
+ android:elevation="@dimen/deep_shortcuts_elevation">
<Space android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:id="@+id/separator"/>
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:id="@+id/separator"/>
</LinearLayout>
diff --git a/res/layout/system_shortcut_rows_container_material_u.xml b/res/layout/system_shortcut_rows_container_material_u.xml
new file mode 100644
index 0000000..006e280
--- /dev/null
+++ b/res/layout/system_shortcut_rows_container_material_u.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/system_shortcuts_container"
+ android:background="@drawable/popup_background_material_u"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tag="@string/popup_container_iterate_children"
+ android:elevation="@dimen/deep_shortcuts_elevation"
+ android:orientation="vertical"/>
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/widget_shortcut_container_material_u.xml
similarity index 71%
copy from res/layout/system_shortcut_icons.xml
copy to res/layout/widget_shortcut_container_material_u.xml
index 775a45f..aab34e3 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/widget_shortcut_container_material_u.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- 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.
@@ -16,17 +16,12 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/system_shortcut_icons"
+ android:id="@+id/widget_shortcut_container"
+ android:background="@drawable/popup_background_material_u"
android:layout_width="match_parent"
android:layout_height="@dimen/system_shortcut_header_height"
android:orientation="horizontal"
android:gravity="end|center_vertical"
- android:background="@drawable/single_item_primary"
android:elevation="@dimen/deep_shortcuts_elevation"
- android:clipToPadding="true">
-
- <Space android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:id="@+id/separator"/>
-</LinearLayout>
+ android:tag="@string/popup_container_iterate_children"
+ android:clipToPadding="true"/>
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index a5f72ef..b76eef7 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -18,7 +18,6 @@
android:id="@+id/widgets_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/bg_rounded_corner_bottom_sheet"
android:paddingTop="@dimen/bottom_sheet_handle_margin"
android:orientation="vertical">
<View
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index e3f1fca..e31bf7a 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -25,7 +25,6 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/bg_widgets_full_sheet"
android:focusable="true"
android:importantForAccessibility="no">
diff --git a/res/layout/widgets_full_sheet_large_screen.xml b/res/layout/widgets_full_sheet_large_screen.xml
new file mode 100644
index 0000000..b99ac5c
--- /dev/null
+++ b/res/layout/widgets_full_sheet_large_screen.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.widget.picker.WidgetsFullSheet xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:theme="?attr/widgetsTheme">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:importantForAccessibility="no">
+
+ <FrameLayout
+ android:id="@+id/recycler_view_container"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintWidth_percent="0.33">
+
+ <TextView
+ android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
+ android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
+
+ <!-- Fast scroller popup -->
+ <com.android.launcher3.views.RecyclerViewFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/fastscroll_end_margin" />
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/search_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:visibility="gone" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/recycler_view_container"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ android:paddingEnd="16dp"
+ android:paddingStart="8dp"
+ android:layout_marginTop="26dp"
+ app:layout_constraintWidth_percent="0.67"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/no_widgets_text"
+ style="@style/PrimaryHeadline"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textSize="18sp"
+ android:visibility="gone"
+ tools:text="No widgets available" />
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/right_pane">
+ <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+ android:id="@+id/recommended_widget_table"
+ android:background="@drawable/widgets_surface_background"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal=
+ "@dimen/widget_list_horizontal_margin_large_screen"
+ android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
+ android:visibility="gone" />
+ </ScrollView>
+ </FrameLayout>
+
+ <View
+ android:id="@+id/collapse_handle"
+ android:layout_width="@dimen/bottom_sheet_handle_width"
+ android:layout_height="@dimen/bottom_sheet_handle_height"
+ android:layout_marginTop="@dimen/bottom_sheet_handle_margin"
+ android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/collapse_handle"
+ android:layout_marginTop="24dp"
+ android:gravity="center_horizontal"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:text="@string/widget_button_text"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="24sp" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.launcher3.widget.picker.WidgetsFullSheet>
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 2819b99..b02e3e3 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -47,6 +47,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/collapse_handle"
android:paddingBottom="0dp"
+ android:clipToOutline="true"
android:orientation="vertical">
<TextView
diff --git a/res/layout/widgets_full_sheet_paged_view_large_screen.xml b/res/layout/widgets_full_sheet_paged_view_large_screen.xml
new file mode 100644
index 0000000..edee352
--- /dev/null
+++ b/res/layout/widgets_full_sheet_paged_view_large_screen.xml
@@ -0,0 +1,123 @@
+<?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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <FrameLayout
+ android:id="@+id/widgets_full_sheet_paged_view_large_screen"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintEnd_toStartOf="@id/scrollView"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintWidth_percent="0.33">
+ <com.android.launcher3.widget.picker.WidgetPagedView
+ android:id="@+id/widgets_view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:descendantFocusability="afterDescendants"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ launcher:pageIndicator="@+id/tabs" >
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/primary_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false" />
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/work_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false" />
+
+ </com.android.launcher3.widget.picker.WidgetPagedView>
+
+ <!-- SearchAndRecommendationsView without the tab layout as well -->
+ <com.android.launcher3.views.StickyHeaderLayout
+ android:id="@+id/search_and_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToOutline="true"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/search_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:clipToPadding="false"
+ android:elevation="0.1dp"
+ android:paddingBottom="8dp"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ launcher:layout_sticky="true">
+
+ <include layout="@layout/widgets_search_bar" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/suggestions_header"
+ android:layout_marginTop="8dp"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:orientation="horizontal">
+ </LinearLayout>
+
+ <com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:paddingVertical="8dp"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:background="?android:attr/colorBackground"
+ style="@style/TextHeadline"
+ launcher:layout_sticky="true">
+
+ <Button
+ android:id="@+id/tab_personal"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
+ android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
+ android:layout_weight="1"
+ android:background="@drawable/all_apps_tabs_background"
+ android:text="@string/widgets_full_sheet_personal_tab"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp"
+ style="?android:attr/borderlessButtonStyle" />
+
+ <Button
+ android:id="@+id/tab_work"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
+ android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
+ android:layout_weight="1"
+ android:background="@drawable/all_apps_tabs_background"
+ android:text="@string/widgets_full_sheet_work_tab"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp"
+ style="?android:attr/borderlessButtonStyle" />
+
+ </com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
+ </com.android.launcher3.views.StickyHeaderLayout>
+ </FrameLayout>
+</merge>
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index 2291943..366d2d2 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -31,6 +31,7 @@
android:layout_below="@id/collapse_handle"
android:paddingBottom="16dp"
android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
+ android:clipToOutline="true"
android:orientation="vertical">
<TextView
diff --git a/res/layout/widgets_full_sheet_recyclerview_large_screen.xml b/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
new file mode 100644
index 0000000..c6a4f62
--- /dev/null
+++ b/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <FrameLayout
+ android:id="@+id/widgets_full_sheet_recyclerview_large_screen"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintEnd_toStartOf="@id/scrollView"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintWidth_percent="0.33">
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/primary_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:clipToPadding="false" />
+
+ <!-- SearchAndRecommendationsView without the tab layout as well -->
+ <com.android.launcher3.views.StickyHeaderLayout
+ android:id="@+id/search_and_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToOutline="true"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/search_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:clipToPadding="false"
+ android:elevation="0.1dp"
+ android:paddingBottom="8dp"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ launcher:layout_sticky="true">
+
+ <include layout="@layout/widgets_search_bar" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/suggestions_header"
+ android:layout_marginTop="8dp"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:orientation="horizontal">
+ </LinearLayout>
+ </com.android.launcher3.views.StickyHeaderLayout>
+ </FrameLayout>
+</merge>
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 35bea27..6d26ce3 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -23,7 +23,8 @@
android:importantForAccessibility="yes"
android:focusable="true"
launcher:appIconSize="48dp"
- android:descendantFocusability="afterDescendants">
+ android:descendantFocusability="afterDescendants"
+ android:background="@drawable/bg_widgets_header" >
<ImageView
android:id="@+id/app_icon"
@@ -65,8 +66,11 @@
<!-- This checkbox is not clickable. The outermost LinearLayout is responsible to handle all
click event and update the checkbox state. -->
- <CheckBox
+ <ImageView
+ android:duplicateParentState="true"
android:id="@+id/toggle"
+ android:alpha=".6"
+ android:src="@drawable/widgets_tray_expand_button"
android:layout_marginHorizontal="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -74,7 +78,6 @@
android:layout_alignParentEnd="true"
android:enabled="false"
android:clickable="false"
- android:importantForAccessibility="no"
- android:button="@drawable/widgets_tray_expand_button"/>
+ android:importantForAccessibility="no" />
</com.android.launcher3.widget.picker.WidgetsListHeader>
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_header_two_pane.xml b/res/layout/widgets_list_row_header_two_pane.xml
new file mode 100644
index 0000000..6465db5
--- /dev/null
+++ b/res/layout/widgets_list_row_header_two_pane.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.widget.picker.WidgetsListHeader xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/widgets_list_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:importantForAccessibility="yes"
+ android:focusable="true"
+ launcher:appIconSize="48dp"
+ android:descendantFocusability="afterDescendants"
+ android:background="@drawable/bg_widgets_header_large_screen" >
+
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="16dp"
+ android:importantForAccessibility="no"
+ tools:src="@drawable/ic_corp"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:duplicateParentState="true">
+
+ <TextView
+ android:id="@+id/app_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textColor="?attr/widgetPickerHeaderAppTitleColor"
+ android:textSize="16sp"
+ android:duplicateParentState="true"
+ tools:text="App name" />
+
+ <TextView
+ android:id="@+id/app_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textColor="?attr/widgetPickerHeaderAppSubtitleColor"
+ android:alpha="0.7"
+ android:duplicateParentState="true"
+ tools:text="m widgets, n shortcuts" />
+
+ </LinearLayout>
+</com.android.launcher3.widget.picker.WidgetsListHeader>
diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml
index ab96b1343..4a32672 100644
--- a/res/layout/widgets_table_container.xml
+++ b/res/layout/widgets_table_container.xml
@@ -16,5 +16,6 @@
<com.android.launcher3.widget.picker.WidgetsListTableView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widgets_table"
+ android:background="@drawable/bg_widgets_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 1794b19..d21289e 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Raak en hou die legstuk om dit op die tuisskerm rond te beweeg"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Voeg by tuisskerm"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by tuisskerm gevoeg"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Voorstelle"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# legstuk}other{# legstukke}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kortpad}other{# kortpaaie}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index be7a737..c34e03b 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ምግብር}one{# ምግብሮች}other{# ምግብሮች}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# አቋራጭ}one{# አቋራጭ}other{# አቋራጮች}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>፣ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 1aaa659..85ebc22 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 5dd751e..a0461bc 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# টা ৱিজেট}one{# টা ৱিজেট}other{# টা ৱিজেট}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# টা শ্বৰ্টকাট}one{# টা শ্বৰ্টকাট}other{# টা শ্বৰ্টকাট}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 9b3d60c..98cd9b4 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Əsas ekranda hərəkət etdirmək üçün vidcetə toxunub saxlayın"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Əsas ekrana əlavə edin"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidceti əsas ekrana əlavə edildi"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Təkliflər"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidcet}other{# vidcet}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# qısayol}other{# qısayol}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 9061ef4..5f9c991 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da biste ga pomerali 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">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlozi"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 6bd6450..a250a69 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# віджэт}one{# віджэт}few{# віджэты}many{# віджэтаў}other{# віджэта}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыкі}many{# ярлыкоў}other{# ярлыка}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 68707a8..47c2b28 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# приспособление}other{# приспособления}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пряк път}other{# преки пътя}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 31704bc..987f4bd 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{#টি উইজেট}one{#টি উইজেট}other{#টি উইজেট}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#টি শর্টকাট}one{#টি শর্টকাট}other{#টি শর্টকাট}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 4b197d7..46bac11 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -37,6 +37,7 @@
<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_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> je dodan na početni ekran"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 275cba2..046ccf1 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén premut el widget per moure\'l per la pantalla d\'inici"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Afegeix a la pantalla d\'inici"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"El widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> s\'ha afegit a la pantalla d\'inici"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggeriments"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# drecera}other{# dreceres}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index af1ed17..49cfa8f 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pokud chcete widgetem pohybovat po ploše, podržte ho"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ # widget}few{# widgety}many{# widgetu}other{# widgetů}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# zkratka}few{# zkratky}many{# zkratky}other{# zkratek}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 2ac056a..aa4135b 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Hold widgetten nede for at flytte den rundt på startskærmen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Føj til startskærm"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetten <xliff:g id="WIDGET_NAME">%1$s</xliff:g> blev føjet til startskærmen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Forslag"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genvej}one{# genvej}other{# genveje}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index c688916..cd5cbc6 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Wenn du das Widget auf dem Startbildschirm verschieben möchtest, halte es gedrückt"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Zum Startbildschirm hinzufügen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-Widget zum Startbildschirm hinzugefügt"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Vorschläge"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# Widget}other{# Widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# Verknüpfung}other{# Verknüpfungen}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 80307c6..7adddf9 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# γραφικό στοιχείο}other{# γραφικά στοιχεία}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# συντόμευση}other{# συντομεύσεις}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 22ab551..ef9dfb3 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 22838ea..a623919 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch & hold the widget to move it around the home screen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 22ab551..ef9dfb3 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 22ab551..ef9dfb3 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index a885f00..da3fea1 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch & hold the widget to move it around the home screen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 3a21f15..a75e436 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén presionado el widget para moverlo por la pantalla principal"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Agregar a pantalla principal"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Se agregó el widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a la pantalla principal"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugerencias"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index af9cc27..827f5c6 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén pulsado el widget para moverlo por la pantalla de inicio"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Añadir a pantalla de inicio"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> añadido a la pantalla de inicio"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugerencias"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index b8d12a3..1886806 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Vidina teisaldamiseks avakuval puudutage vidinat ja hoidke seda all"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Lisa avakuvale"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g> lisati avakuvale"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Soovitused"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidin}other{# vidinat}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# otsetee}other{# otseteed}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 530a5a0..9f9f560 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Widgeta hasierako pantailan zehar mugitzeko, eduki ezazu sakatuta"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Gehitu hasierako pantailan"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta hasierako pantailan gehitu da"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Iradokizunak"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lasterbide}other{# lasterbide}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index cb811f3..67a849f 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ابزارک}one{# ابزارک}other{# ابزارک}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# میانبر}one{# میانبر}other{# میانبر}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>،<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 92fe859..28b07b9 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Voit siirtää widgetiä aloitusnäytöllä koskettamalla sitä pitkään"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Lisää aloitusnäytölle"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget lisätty aloitusnäytölle: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ehdotukset"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetiä}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pikakuvake}other{# pikakuvaketta}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index db35665..1cc0b3c 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Maintenez le doigt sur le widget pour le déplacer sur l\'écran d\'accueil"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a été ajouté à l\'écran d\'accueil"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 571a03e..803c12b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Appuyez de manière prolongée sur le widget pour le déplacer sur l\'écran d\'accueil"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 2ed64a1..5b5dd41 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén premido o widget para movelo pola pantalla de inicio"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Engadir á pantalla de inicio"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Engadiuse o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> á pantalla de inicio"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suxestións"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atallo}other{# atallos}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 719f531..53f10a1 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# વિજેટ}one{# વિજેટ}other{# વિજેટ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# શૉર્ટકટ}one{# શૉર્ટકટ}other{# શૉર્ટકટ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index eacd252..b4d358b 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}one{# विजेट}other{# विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}one{# शॉर्टकट}other{# शॉर्टकट}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index eeeade0..66b5ef9 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite widget da biste ga pomicali po početnom zaslonu"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni zaslon"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> dodan je na početni zaslon"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}few{# widgeta}other{# widgeta}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečac}one{# prečac}few{# prečaca}other{# prečaca}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 330fd69..f5f62bc 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tartsa lenyomva a modult a kezdőképernyőn való mozgatáshoz"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Hozzáadás a kezdőképernyőhöz"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadva a kezdőképernyőhöz"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Javaslatok"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# modul}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# gyorsparancs}other{# gyorsparancs}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index cf01672..b58d975 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# վիջեթ}one{# վիջեթ}other{# վիջեթ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# դյուրանցում}one{# դյուրանցում}other{# դյուրանցում}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index fdccae3..5738b8b 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Sentuh lama widget untuk memindahkannya di sekitar layar utama"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan ke layar utama"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan ke layar utama"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Saran"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 8ddfddc..2a74664 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Haltu fingri á græjunni til að hreyfa hana um heimaskjáinn"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Bæta á heimaskjá"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> græju bætt við heimaskjá"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Tillögur"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# græja}one{# græja}other{# græjur}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# flýtileið}one{# flýtileið}other{# flýtileiðir}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 1c7cbe1..929838e 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tocca e tieni premuto il widget per spostarlo nella schermata Home"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Aggiungi alla schermata Home"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> aggiunto alla schermata Home"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggerimenti"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# scorciatoia}other{# scorciatoie}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 3bb65b4..09c4da0 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ווידג\'ט אחד}one{# ווידג\'טים}two{# ווידג\'טים}other{# ווידג\'טים}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}one{# קיצורי דרך}two{# קיצורי דרך}other{# קיצורי דרך}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 02dcba6..8db2b66 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 件のウィジェット}other{# 件のウィジェット}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 件のショートカット}other{# 件のショートカット}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 2e684b2..c730212 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ვიჯეტი}other{# ვიჯეტი}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# მალსახმობი}other{# მალსახმობი}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 4caffb3..6484c6d 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# таңбаша}other{# таңбаша}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 1039a89..dd17f76 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ធាតុក្រាហ្វិក #}other{ធាតុក្រាហ្វិក #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ផ្លូវកាត់ #}other{ផ្លូវកាត់ #}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index fa97690..46b7fd5 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ವಿಜೆಟ್}one{# ವಿಜೆಟ್ಗಳು}other{# ವಿಜೆಟ್ಗಳು}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ಶಾರ್ಟ್ಕಟ್}one{# ಶಾರ್ಟ್ಕಟ್ಗಳು}other{# ಶಾರ್ಟ್ಕಟ್ಗಳು}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index b1c9a16..ba2ac16 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{위젯 #개}other{위젯 #개}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{바로가기 #개}other{바로가기 #개}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 18672f5..cbbbf73 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ыкчам баскыч}other{# ыкчам баскыч}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 422240c..d0c26aa 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -23,7 +23,6 @@
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">15.28dp</dimen>
- <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
<dimen name="dynamic_grid_drop_target_size">36dp</dimen>
<dimen name="cell_layout_padding">20dp</dimen>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 5a773ae..8380eec 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ວິດເຈັດ}other{# ວິດເຈັດ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ທາງລັດ}other{# ທາງລັດ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index a01c1cd..e4c40f3 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Paliesdami ir palaikydami valdiklį galite judėti pagrindiniame ekrane"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Pridėti prie pagrindinio ekrano"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Valdiklis „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ pridėtas prie pagrindinio ekrano"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Pasiūlymai"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# valdiklis}one{# valdiklis}few{# valdikliai}many{# valdiklio}other{# valdiklių}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# spartusis klavišas}one{# spartusis klavišas}few{# spartieji klavišai}many{# sparčiojo klavišo}other{# sparčiųjų klavišų}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index a5e3ed8..f99d5ba 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pieskarieties logrīkam un turiet to, lai to pārvietotu pa sākuma ekrānu."</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Pievienot sākuma ekrānam"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Logrīks “<xliff:g id="WIDGET_NAME">%1$s</xliff:g>” ir pievienots sākuma ekrānam"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ieteikumi"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# logrīks}zero{# logrīku}one{# logrīks}other{# logrīki}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# saīsne}zero{# saīšņu}one{# saīsne}other{# saīsnes}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 8418ed2..d863c35 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}other{# виџети}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# кратенка}one{# кратенка}other{# кратенки}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 945e5ba..c7ededf 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# വിജറ്റ്}other{# വിജറ്റുകൾ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# കുറുക്കുവഴി}other{# കുറുക്കുവഴികൾ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index a3754ce..73ea219 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# товчлол}other{# товчлол}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index ac7a09b..8371648 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}other{# शॉर्टकट}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 263ef48..72a95cd 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Sentuh & tahan widget untuk menggerakkan widget di sekitar skrin utama"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan pada skrin utama"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan pada skrin utama"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Cadangan"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index e62e050..001bae3 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ဝိဂျက် # ခု}other{ဝိဂျက် # ခု}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ဖြတ်လမ်းလင့်ခ် # ခု}other{ဖြတ်လမ်းလင့်ခ် # ခု}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>၊ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2471081..8158220 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Trykk og hold på modulen for å bevege den rundt på startskjermen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Legg til på startskjermen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen er lagt til på startskjermen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Forslag"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# moduler}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snarvei}other{# snarveier}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 0cd7f95..7d6e83d 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# वटा विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# सर्टकट}other{# वटा सर्टकट}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 5e6ed97..452b166 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -37,6 +37,7 @@
<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_to_home_screen" msgid="9168649446635919791">"Toevoegen aan startscherm"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toegevoegd aan startscherm"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggesties"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snelkoppeling}other{# snelkoppelingen}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index a0509b1..dc489bd 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{#ଟି ୱିଜେଟ୍}other{#ଟି ୱିଜେଟ୍}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#ଟି ସର୍ଟକଟ୍}other{#ଟି ସର୍ଟକଟ୍}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 2bb7274..1a364b7 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ਵਿਜੇਟ}one{# ਵਿਜੇਟ}other{# ਵਿਜੇਟ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ਸ਼ਾਰਟਕੱਟ}one{# ਸ਼ਾਰਟਕੱਟ}other{# ਸ਼ਾਰਟਕੱਟ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f79d0d2..45ad46c 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Kliknij i przytrzymaj widżet, aby poruszać nim po ekranie głównym"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestie"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widżet}few{# widżety}many{# widżetów}other{# widżetu}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# skrót}few{# skróty}many{# skrótów}other{# skrótu}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index db86366..b56f857 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Toque sem soltar no widget para o mover no ecrã principal"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar ao ecrã principal"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado ao ecrã principal"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestões"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}other{# atalhos}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index db057ad..b6bbbaf 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -34,9 +34,10 @@
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Toque no widget e o mantenha pressionado para definir a posição dele na tela inicial"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Toque no widget e o pressione para definir a posição dele na tela inicial"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar à tela inicial"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado à tela inicial"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestões"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}one{# atalho}other{# atalhos}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 242649e..8063174 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Atinge lung widgetul pentru a-l muta pe ecranul de pornire"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Adaugă pe ecranul de pornire"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a fost adăugat pe ecranul de pornire"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestii"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}few{# widgeturi}other{# de widgeturi}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# comandă rapidă}few{# comenzi rapide}other{# de comenzi rapide}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g> <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index c14e4d1..58b039d 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}one{# виджет}few{# виджета}many{# виджетов}other{# виджета}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыка}many{# ярлыков}other{# ярлыка}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 27a81cf..e4b919c 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{විජට් #}one{විජට් #}other{විජට් #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{කෙටි මං #}one{කෙටි මං #}other{කෙටි මං #}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 973ec86..7060bcc 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pridržaním môžete miniaplikáciu posúvať po ploche"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Pridať na plochu"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Na plochu bola pridaná miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikácia}few{# miniaplikácie}many{# widgets}other{# miniaplikácií}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# odkaz}few{# odkazy}many{# shortcuts}other{# odkazov}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index a2720b6..ef3c3fd 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dotaknite se pripomočka in ga pridržite, če ga želite premikati po začetnem zaslonu."</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na začetni zaslon"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Pripomoček »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>« je dodan na začetni zaslon."</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlogi"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# pripomoček}one{# pripomoček}two{# pripomočka}few{# pripomočki}other{# pripomočkov}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# bližnjica}one{# bližnjica}two{# bližnjici}few{# bližnjice}other{# bližnjic}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index dd25a36..5f0e328 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Prek dhe mbaj të shtypur miniaplikacionin për ta lëvizur atë nëpër ekranin bazë"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Shto në ekranin bazë"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Miniaplikacioni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> u shtua në ekranin bazë"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugjerime"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikacion}other{# miniaplikacione}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shkurtore}other{# shkurtore}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 14212d7..4069745 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}few{# виџета}other{# виџета}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пречица}one{# пречица}few{# пречице}other{# пречица}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 05cb231..205430b 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tryck länge på widgeten om du vill flytta den på startskärmen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Lägg till på startskärmen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g> har lagts till på startskärmen"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Förslag"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetar}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genväg}other{# genvägar}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 5624d4a..3897ad2 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Gusa na ushikilie wijeti ili uisogeze kwenye skrini ya kwanza"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Weka kwenye skrini ya kwanza"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Umeongeza wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g> kwenye skrini ya kwanza"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Mapendekezo"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{Wijeti #}other{Wijeti #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{Njia # ya mkato}other{Njia # za mkato}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index 63970cd..92f6881 100644
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -30,6 +30,4 @@
<dimen name="dynamic_grid_edge_margin">11.33dp</dimen>
<dimen name="cell_layout_padding">11.33dp</dimen>
-<!-- AllApps -->
- <dimen name="all_apps_bottom_sheet_horizontal_padding">52dp</dimen>
</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index d69e777..cc1f09e 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -26,7 +26,6 @@
<!-- AllApps -->
<dimen name="all_apps_search_bar_content_overlap">0dp</dimen>
- <dimen name="all_apps_bottom_sheet_horizontal_padding">48dp</dimen>
<!-- Fast scroll -->
<dimen name="fastscroll_popup_width">75dp</dimen>
@@ -36,7 +35,6 @@
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">9dp</dimen>
- <dimen name="dynamic_grid_icon_drawable_padding">7dp</dimen>
<dimen name="cell_layout_padding">9dp</dimen>
<!-- Hotseat -->
diff --git a/res/values-sw600dp/styles.xml b/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..63bd46b
--- /dev/null
+++ b/res/values-sw600dp/styles.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+
+<resources>
+ <style name="CellStyleDefault">
+ <item name="iconDrawablePadding">7dp</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index 235631d..b89910d 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -22,9 +22,6 @@
<dimen name="dynamic_grid_edge_margin">21.93dp</dimen>
<dimen name="cell_layout_padding">29.33dp</dimen>
-<!-- AllApps -->
- <dimen name="all_apps_bottom_sheet_horizontal_padding">32dp</dimen>
-
<!-- Dragging-->
<dimen name="drop_target_top_margin">0dp</dimen>
<dimen name="drop_target_bottom_margin">32dp</dimen>
@@ -34,6 +31,7 @@
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">49dp</dimen>
+ <dimen name="widget_list_horizontal_margin_large_screen">24dp</dimen>
<!-- Bottom sheet-->
<dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 09b2d6f..d7a5881 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -18,9 +18,6 @@
<!-- PagedView -->
<dimen name="min_page_snap_velocity">3400dp</dimen>
-<!-- AllApps -->
- <dimen name="all_apps_bottom_sheet_horizontal_padding">28dp</dimen>
-
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">27.59dp</dimen>
<dimen name="cell_layout_padding">36dp</dimen>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 4213ea4..a2c0dd6 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# விட்ஜெட்}other{# விட்ஜெட்டுகள்}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ஷார்ட்கட்}other{# ஷார்ட்கட்கள்}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index e8ef4fa..5c719d9 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# విడ్జెట్}other{# విడ్జెట్లు}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# షార్ట్కట్}other{# షార్ట్కట్లు}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 85289e4..f01b3ec 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{วิดเจ็ต # รายการ}other{วิดเจ็ต # รายการ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ทางลัด # รายการ}other{ทางลัด # รายการ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index ec6bc5f..719d767 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pindutin nang matagal ang widget para ilipat-lipat ito sa home screen"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Idagdag sa home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Idinagdag sa home screen ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Mga Suhestyon"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# na widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}one{# shortcut}other{# na shortcut}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index c485994..ccfc034 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Ana ekranda taşımak için widget\'a dokunup basılı tutun"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Ana ekrana ekle"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ana ekrana eklendi"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Öneriler"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kısayol}other{# kısayol}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index d375756..5848d38 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# віджет}one{# віджет}few{# віджети}many{# віджетів}other{# віджета}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлик}one{# ярлик}few{# ярлики}many{# ярликів}other{# ярлика}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 13a0962..ea3631a 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ویجیٹ}other{# ویجیٹس}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# شارٹ کٹ}other{# شارٹ کٹس}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index a3859fd..f53aaf4 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Bosh ekranda surish uchun vidjet ustiga bosib turing"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Bosh ekranga chiqarish"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti bosh ekranga qoʻshildi"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Takliflar"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ta vidjet}other{# ta vidjet}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ta yorliq}other{# ta yorliq}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 63a5454..f87d9fc 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -64,4 +64,6 @@
<color name="all_apps_button_color_light">@android:color/system_neutral2_700</color>
<color name="all_apps_button_color_dark">@android:color/system_neutral2_200</color>
+
+ <color name="widget_picker_background_selected">@android:color/system_accent2_100</color>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 6924aed..43a6eb4 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Chạm và giữ tiện ích để di chuyển tiện ích đó xung quanh màn hình chính"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Thêm vào màn hình chính"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Đã thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g> vào màn hình chính"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Nội dung đề xuất"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# tiện ích}other{# tiện ích}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lối tắt}other{# lối tắt}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 5011df8..bdff8d5 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 个微件}other{# 个微件}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 个快捷方式}other{# 个快捷方式}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>,<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index d14ce53..44d3932 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 個小工具}other{# 個小工具}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 45cbc7f..6900c39 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -37,6 +37,7 @@
<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>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 項小工具}other{# 項小工具}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index ec4a0d9..976594c 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -37,6 +37,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Thinta uphinde ubambe iwijethi ukuyihambisa kusikrini sasekhaya"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Faka kusikrini sasekhaya"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g> yengezwe kusikrini sasekhaya"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Iziphakamiso"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{iwijethi #}one{amawijethi #}other{amawijethi #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{isinqamuleli #}one{izinqamuleli #}other{izinqamuleli #}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index e6f285c..f70937a 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -55,6 +55,8 @@
<attr name="dropTargetHoverTextColor" format="color" />
<attr name="preloadIconAccentColor" format="color" />
<attr name="preloadIconBackgroundColor" format="color" />
+ <attr name="widgetPickerHeaderAppTitleColor" format="color"/>
+ <attr name="widgetPickerHeaderAppSubtitleColor" format="color"/>
<!-- BubbleTextView specific attributes. -->
<declare-styleable name="BubbleTextView">
@@ -151,6 +153,9 @@
<!-- Support attributes in FolderStyle -->
<attr name="folderStyle" format="reference" />
+ <!-- Support attributes in AllAppsStyle. Defaults to AllAppsStyleDefault -->
+ <attr name="allAppsStyle" format="reference" />
+
<!-- numAllAppsColumns defaults to numColumns, if not specified -->
<attr name="numAllAppsColumns" format="integer" />
<!-- Number of columns to use when extending the all-apps size,
@@ -221,6 +226,21 @@
<attr name="alignOnIcon" format="boolean" />
</declare-styleable>
+ <!-- Responsive grids attributes -->
+ <declare-styleable name="WorkspaceSpec">
+ <attr name="specType" format="integer">
+ <enum name="height" value="0" />
+ <enum name="width" value="1" />
+ </attr>
+ <attr name="maxAvailableSize" format="dimension" />
+ </declare-styleable>
+
+ <declare-styleable name="SpecSize">
+ <attr name="fixedSize" format="dimension" />
+ <attr name="ofAvailableSpace" format="float" />
+ <attr name="ofRemainderSpace" format="float" />
+ </declare-styleable>
+
<declare-styleable name="ProfileDisplayOption">
<attr name="name" />
<attr name="minWidthDps" format="float" />
@@ -418,6 +438,10 @@
<attr name="iconDrawablePadding" format="dimension" />
</declare-styleable>
+ <declare-styleable name="AllAppsStyle">
+ <attr name="horizontalPadding" format="dimension" />
+ </declare-styleable>
+
<declare-styleable name="ShadowDrawable">
<attr name="android:src" />
<attr name="android:shadowColor" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 321aef5..82758bf 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -21,7 +21,6 @@
<!-- Dynamic Grid -->
<dimen name="dynamic_grid_edge_margin">10.77dp</dimen>
<dimen name="dynamic_grid_left_right_margin">8dp</dimen>
- <dimen name="dynamic_grid_icon_drawable_padding">7dp</dimen>
<!-- Minimum amount of next page visible in spring loaded mode -->
<dimen name="dynamic_grid_spring_loaded_min_next_space_visible">24dp</dimen>
@@ -131,7 +130,6 @@
<dimen name="all_apps_content_fade_in_offset">150dp</dimen>
<dimen name="all_apps_tip_bottom_margin">8dp</dimen>
<dimen name="all_apps_height_extra">6dp</dimen>
- <dimen name="all_apps_bottom_sheet_horizontal_padding">0dp</dimen>
<dimen name="all_apps_paged_view_top_padding">40dp</dimen>
<dimen name="all_apps_icon_drawable_padding">8dp</dimen>
@@ -193,6 +191,7 @@
<dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
<dimen name="widget_list_entry_spacing">2dp</dimen>
<dimen name="widget_list_horizontal_margin">16dp</dimen>
+ <dimen name="widget_list_horizontal_margin_large_screen">24dp</dimen>
<dimen name="widget_preview_shadow_blur">0.5dp</dimen>
<dimen name="widget_preview_key_shadow_distance">1dp</dimen>
@@ -349,7 +348,7 @@
<dimen name="developer_options_filter_margins">10dp</dimen>
<!-- Theming related -->
- <dimen name="default_dialog_corner_radius">8dp</dimen>
+ <dimen name="default_dialog_corner_radius">26dp</dimen>
<dimen name="dialogCornerRadius">@dimen/default_dialog_corner_radius</dimen>
<!-- Onboarding bottomsheet related -->
@@ -416,10 +415,6 @@
<dimen name="split_instructions_elevation">1dp</dimen>
<dimen name="split_instructions_horizontal_padding">24dp</dimen>
<dimen name="split_instructions_vertical_padding">12dp</dimen>
- <dimen name="split_instructions_bottom_margin_tablet_landscape">32dp</dimen>
- <dimen name="split_instructions_bottom_margin_tablet_portrait">44dp</dimen>
- <dimen name="split_instructions_bottom_margin_twopanels_landscape">33dp</dimen>
- <dimen name="split_instructions_bottom_margin_twopanels_portrait">51dp</dimen>
<dimen name="split_instructions_bottom_margin_phone_landscape">24dp</dimen>
<dimen name="split_instructions_bottom_margin_phone_portrait">60dp</dimen>
diff --git a/res/values/id.xml b/res/values/id.xml
index 52a7e98..375750f 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -19,7 +19,6 @@
<item type="id" name="view_type_widgets_space" />
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
- <item type="id" name="view_type_widgets_search_header" />
<!-- Used for A11y actions in staged split to identify each task uniquely -->
<item type="id" name="split_topLeft_appInfo" />
<item type="id" name="split_bottomRight_appInfo" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a2ebf16..190a3a5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -63,6 +63,9 @@
<!-- Accessibility spoken message announced when a widget gets added to the home screen using a
button in a dialog. [CHAR_LIMIT=none] -->
<string name="added_to_home_screen_accessibility_text"><xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget added to home screen</string>
+ <!-- Widget suggestions header title in the full widgets picker for large screen devices
+ in landscape mode. [CHAR_LIMIT=50] -->
+ <string name="suggested_widgets_header_title">Suggestions</string>
<!-- Label for showing the number of widgets an app has in the full widgets picker.
[CHAR_LIMIT=25][ICU SYNTAX] -->
<string name="widgets_count">
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6b57532..474a289 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -176,10 +176,14 @@
<item name="android:colorPrimaryDark">#E8EAED</item>
<item name="android:textColorSecondary">?android:attr/textColorPrimary</item>
<item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
+ <item name="widgetPickerHeaderAppTitleColor">@color/app_title_text_light</item>
+ <item name="widgetPickerHeaderAppSubtitleColor">@color/app_subtitle_text_light</item>
</style>
<style name="WidgetContainerTheme.Dark" parent="AppTheme.Dark">
<item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
<item name="android:colorPrimaryDark">#616161</item> <!-- Gray 700 -->
+ <item name="widgetPickerHeaderAppTitleColor">@color/app_title_text_dark</item>
+ <item name="widgetPickerHeaderAppSubtitleColor">@color/app_subtitle_text_dark</item>
</style>
<style name="FastScrollerPopup" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
@@ -304,4 +308,8 @@
<item name="iconDrawablePadding">7dp</item>
</style>
+ <style name="AllAppsStyleDefault">
+ <item name="horizontalPadding">16dp</item>
+ </style>
+
</resources>
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index 8a0c909..284ab9e 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -50,10 +50,4 @@
launcher:logIdOn="615"
launcher:logIdOff="616" />
- <androidx.preference.PreferenceScreen
- android:key="pref_developer_options"
- android:persistent="false"
- android:title="@string/developer_options_title"
- android:fragment="com.android.launcher3.settings.DeveloperOptionsFragment"/>
-
</androidx.preference.PreferenceScreen>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index edbce10..df38c26 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -104,11 +104,17 @@
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
private float mTranslationXForTaskbarAlignmentAnimation = 0f;
+ private float mTranslationYForTaskbarAlignmentAnimation = 0f;
+
+ private float mTranslationXForTaskbarRevealAnimation = 0f;
+ private float mTranslationYForTaskbarRevealAnimation = 0f;
private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0);
private float mScaleForReorderBounce = 1f;
+ private float mTranslationXForTaskbarAllAppsIcon = 0f;
+
private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
= new Property<BubbleTextView, Float>(Float.TYPE, "dotScale") {
@Override
@@ -370,9 +376,7 @@
@UiThread
protected void applyIconAndLabel(ItemInfoWithIcon info) {
- boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
- || mDisplay == DISPLAY_TASKBAR;
- int flags = useTheme ? FLAG_THEMED : 0;
+ int flags = shouldUseTheme() ? FLAG_THEMED : 0;
if (mHideBadge) {
flags |= FLAG_NO_BADGE;
}
@@ -384,6 +388,11 @@
applyLabel(info);
}
+ protected boolean shouldUseTheme() {
+ return mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
+ || mDisplay == DISPLAY_TASKBAR;
+ }
+
@UiThread
private void applyLabel(ItemInfoWithIcon info) {
setText(info.title);
@@ -952,11 +961,26 @@
}
private void updateTranslation() {
- super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x
+ super.setTranslationX(mTranslationForReorderBounce.x
+ + mTranslationForReorderPreview.x
+ + mTranslationXForTaskbarAllAppsIcon
+ mTranslationForMoveFromCenterAnimation.x
- + mTranslationXForTaskbarAlignmentAnimation);
- super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y
- + mTranslationForMoveFromCenterAnimation.y);
+ + mTranslationXForTaskbarAlignmentAnimation
+ + mTranslationXForTaskbarRevealAnimation
+ );
+ super.setTranslationY(mTranslationForReorderBounce.y
+ + mTranslationForReorderPreview.y
+ + mTranslationForMoveFromCenterAnimation.y
+ + mTranslationYForTaskbarAlignmentAnimation
+ + mTranslationYForTaskbarRevealAnimation);
+ }
+
+ /**
+ * Sets translationX for taskbar all apps icon
+ */
+ public void setTranslationXForTaskbarAllAppsIcon(float translationX) {
+ mTranslationXForTaskbarAllAppsIcon = translationX;
+ updateTranslation();
}
public void setReorderBounceOffset(float x, float y) {
@@ -1012,6 +1036,51 @@
return mTranslationXForTaskbarAlignmentAnimation;
}
+ /**
+ * Sets translationX for taskbar to launcher alignment animation
+ */
+ public void setTranslationYForTaskbarAlignmentAnimation(float translationY) {
+ mTranslationYForTaskbarAlignmentAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translationY value for taskbar to launcher alignment animation
+ */
+ public float getTranslationYForTaskbarAlignmentAnimation() {
+ return mTranslationYForTaskbarAlignmentAnimation;
+ }
+
+ /**
+ * Sets translationX value for taskbar reveal animation
+ */
+ public void setTranslationXForTaskbarRevealAnimation(float translationX) {
+ mTranslationXForTaskbarRevealAnimation = translationX;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translation values for taskbar reveal animation
+ */
+ public float getTranslationXForTaskbarRevealAnimation() {
+ return mTranslationXForTaskbarRevealAnimation;
+ }
+
+ /**
+ * Sets translationY value for taskbar reveal animation
+ */
+ public void setTranslationYForTaskbarRevealAnimation(float translationY) {
+ mTranslationYForTaskbarRevealAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translationY values for taskbar reveal animation
+ */
+ public float getTranslationYForTaskbarRevealAnimation() {
+ return mTranslationYForTaskbarRevealAnimation;
+ }
+
public View getView() {
return this;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0070f95..87ee4f6 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -190,10 +190,10 @@
public final int hotseatQsbVisualHeight;
private final int hotseatQsbShadowHeight;
public int hotseatBorderSpace;
- private int minHotseatIconSpacePx;
- private int minHotseatQsbWidthPx;
- private final int maxHotseatIconSpacePx;
- private int inlineNavButtonsEndSpacing;
+ private final int mMinHotseatIconSpacePx;
+ private final int mMinHotseatQsbWidthPx;
+ private final int mMaxHotseatIconSpacePx;
+ private final int mInlineNavButtonsEndSpacingPx;
// Bottom sheets
public int bottomSheetTopPadding;
@@ -404,6 +404,7 @@
allAppsBorderSpacePx = new Point(
pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].x, mMetrics),
pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].y, mMetrics));
+ setupAllAppsStyle(context);
workspacePageIndicatorHeight = res.getDimensionPixelSize(
R.dimen.workspace_page_indicator_height);
@@ -489,7 +490,8 @@
hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
updateHotseatSizes(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
if (areNavButtonsInline && !isPhone) {
- inlineNavButtonsEndSpacing = res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing);
+ mInlineNavButtonsEndSpacingPx =
+ res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing);
/*
* 3 nav buttons +
* Spacing between nav buttons +
@@ -497,9 +499,9 @@
*/
hotseatBarEndOffset = 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
+ 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween)
- + inlineNavButtonsEndSpacing;
+ + mInlineNavButtonsEndSpacingPx;
} else {
- inlineNavButtonsEndSpacing = 0;
+ mInlineNavButtonsEndSpacingPx = 0;
hotseatBarEndOffset = 0;
}
@@ -546,9 +548,9 @@
cellLayoutPadding);
updateWorkspacePadding();
- minHotseatIconSpacePx = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space);
- minHotseatQsbWidthPx = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width);
- maxHotseatIconSpacePx = areNavButtonsInline
+ mMinHotseatIconSpacePx = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space);
+ mMinHotseatQsbWidthPx = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width);
+ mMaxHotseatIconSpacePx = areNavButtonsInline
? res.getDimensionPixelSize(R.dimen.max_hotseat_icon_space) : Integer.MAX_VALUE;
// Hotseat and QSB width depends on updated cellSize and workspace padding
recalculateHotseatWidthAndBorderSpace();
@@ -577,15 +579,16 @@
dimensionOverrideProvider.accept(this);
// This is done last, after iconSizePx is calculated above.
- mDotRendererWorkSpace = createDotRenderer(iconSizePx, dotRendererCache);
- mDotRendererAllApps = createDotRenderer(allAppsIconSizePx, dotRendererCache);
+ mDotRendererWorkSpace = createDotRenderer(context, iconSizePx, dotRendererCache);
+ mDotRendererAllApps = createDotRenderer(context, allAppsIconSizePx, dotRendererCache);
}
private static DotRenderer createDotRenderer(
- int size, @NonNull SparseArray<DotRenderer> cache) {
+ @NonNull Context context, int size, @NonNull SparseArray<DotRenderer> cache) {
DotRenderer renderer = cache.get(size);
if (renderer == null) {
- renderer = new DotRenderer(size, getShapePath(DEFAULT_DOT_SIZE), DEFAULT_DOT_SIZE);
+ renderer = new DotRenderer(size, getShapePath(context, DEFAULT_DOT_SIZE),
+ DEFAULT_DOT_SIZE);
cache.put(size, renderer);
}
return renderer;
@@ -659,39 +662,39 @@
}
// The side space with inline buttons should be what is defined in InvariantDeviceProfile
- int sideSpace = inlineNavButtonsEndSpacing;
- int maxHotseatWidth = availableWidthPx - sideSpace - hotseatBarEndOffset;
- int maxHotseatIconsWidth = maxHotseatWidth - (isQsbInline ? hotseatQsbWidth : 0);
- hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidth,
+ int sideSpacePx = mInlineNavButtonsEndSpacingPx;
+ int maxHotseatWidthPx = availableWidthPx - sideSpacePx - hotseatBarEndOffset;
+ int maxHotseatIconsWidthPx = maxHotseatWidthPx - (isQsbInline ? hotseatQsbWidth : 0);
+ hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidthPx,
(isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1);
- if (hotseatBorderSpace >= minHotseatIconSpacePx) {
+ if (hotseatBorderSpace >= mMinHotseatIconSpacePx) {
return;
}
// Border space can't be less than the minimum
- hotseatBorderSpace = minHotseatIconSpacePx;
+ hotseatBorderSpace = mMinHotseatIconSpacePx;
int requiredWidth = getHotseatRequiredWidth();
// If there is an inline qsb, change its size
if (isQsbInline) {
- hotseatQsbWidth -= requiredWidth - maxHotseatWidth;
- if (hotseatQsbWidth >= minHotseatQsbWidthPx) {
+ hotseatQsbWidth -= requiredWidth - maxHotseatWidthPx;
+ if (hotseatQsbWidth >= mMinHotseatQsbWidthPx) {
return;
}
// QSB can't be less than the minimum
- hotseatQsbWidth = minHotseatQsbWidthPx;
+ hotseatQsbWidth = mMinHotseatQsbWidthPx;
}
- maxHotseatIconsWidth = maxHotseatWidth - (isQsbInline ? hotseatQsbWidth : 0);
+ maxHotseatIconsWidthPx = maxHotseatWidthPx - (isQsbInline ? hotseatQsbWidth : 0);
// If it still doesn't fit, start removing icons
do {
numShownHotseatIcons--;
- hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidth,
+ hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidthPx,
(isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1);
- } while (hotseatBorderSpace < minHotseatIconSpacePx && numShownHotseatIcons > 1);
+ } while (hotseatBorderSpace < mMinHotseatIconSpacePx && numShownHotseatIcons > 1);
}
@@ -810,9 +813,6 @@
int cellLayoutHorizontalPadding =
(cellLayoutPaddingPx.left + cellLayoutPaddingPx.right) / 2;
if (isTablet) {
- allAppsLeftRightPadding =
- res.getDimensionPixelSize(R.dimen.all_apps_bottom_sheet_horizontal_padding);
-
int usedWidth = (allAppsCellWidthPx * numShownAllAppsColumns)
+ (allAppsBorderSpacePx.x * (numShownAllAppsColumns - 1))
+ allAppsLeftRightPadding * 2;
@@ -823,6 +823,20 @@
}
}
+ private void setupAllAppsStyle(Context context) {
+ TypedArray allAppsStyle;
+ if (inv.allAppsStyle != INVALID_RESOURCE_HANDLE) {
+ allAppsStyle = context.obtainStyledAttributes(inv.allAppsStyle,
+ R.styleable.AllAppsStyle);
+ } else {
+ allAppsStyle = context.obtainStyledAttributes(R.style.AllAppsStyleDefault,
+ R.styleable.AllAppsStyle);
+ }
+ allAppsLeftRightPadding = allAppsStyle.getDimensionPixelSize(
+ R.styleable.AllAppsStyle_horizontalPadding, 0);
+ allAppsStyle.recycle();
+ }
+
/**
* Returns the amount of extra (or unused) vertical space.
*/
@@ -980,10 +994,10 @@
*/
private int calculateHotseatBorderSpace(float hotseatWidthPx, int numExtraBorder) {
float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons;
- int hotseatBorderSpace =
+ int hotseatBorderSpacePx =
(int) (hotseatWidthPx - hotseatIconsTotalPx)
/ (numShownHotseatIcons - 1 + numExtraBorder);
- return Math.min(hotseatBorderSpace, maxHotseatIconSpacePx);
+ return Math.min(hotseatBorderSpacePx, mMaxHotseatIconSpacePx);
}
@@ -1302,23 +1316,29 @@
hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx;
int hotseatWidth = getHotseatRequiredWidth();
- int leftSpacing = (availableWidthPx - hotseatWidth) / 2;
- int rightSpacing = leftSpacing;
+ int startSpacing;
+ int endSpacing;
// Hotseat aligns to the left with nav buttons
if (hotseatBarEndOffset > 0) {
- leftSpacing = inlineNavButtonsEndSpacing;
- rightSpacing = availableWidthPx - hotseatWidth - leftSpacing + hotseatBorderSpace;
+ startSpacing = mInlineNavButtonsEndSpacingPx;
+ endSpacing = availableWidthPx - hotseatWidth - startSpacing + hotseatBorderSpace;
+ } else {
+ startSpacing = (availableWidthPx - hotseatWidth) / 2;
+ endSpacing = startSpacing;
}
+ startSpacing += getAdditionalQsbSpace();
- hotseatBarPadding.set(leftSpacing, hotseatBarTopPadding, rightSpacing,
- hotseatBarBottomPadding);
-
+ hotseatBarPadding.top = hotseatBarTopPadding;
+ hotseatBarPadding.bottom = hotseatBarBottomPadding;
boolean isRtl = Utilities.isRtl(context.getResources());
if (isRtl) {
- hotseatBarPadding.right += getAdditionalQsbSpace();
+ hotseatBarPadding.left = endSpacing;
+ hotseatBarPadding.right = startSpacing;
} else {
- hotseatBarPadding.left += getAdditionalQsbSpace();
+ hotseatBarPadding.left = startSpacing;
+ hotseatBarPadding.right = endSpacing;
}
+
} else if (isScalableGrid) {
int sideSpacing = (availableWidthPx - hotseatQsbWidth) / 2;
hotseatBarPadding.set(sideSpacing,
@@ -1397,14 +1417,7 @@
*/
public int getOverviewActionsClaimedSpaceBelow() {
if (isTaskbarPresent) {
- if (FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
- return transientTaskbarSize + transientTaskbarMargin * 2;
- }
-
- return isGestureMode
- ? stashedTaskbarSize
- // Align vertically to where nav buttons are.
- : ((taskbarSize - overviewActionsHeight) / 2) + getTaskbarOffsetY();
+ return transientTaskbarSize + transientTaskbarMargin * 2;
}
return mInsets.bottom;
}
@@ -1577,6 +1590,8 @@
writer.println(prefix + pxToDpStr("iconTextSizePx", iconTextSizePx));
writer.println(prefix + pxToDpStr("iconDrawablePaddingPx", iconDrawablePaddingPx));
+ writer.println(prefix + "\tinv.numFolderRows: " + inv.numFolderRows);
+ writer.println(prefix + "\tinv.numFolderColumns: " + inv.numFolderColumns);
writer.println(prefix + pxToDpStr("folderCellWidthPx", folderCellWidthPx));
writer.println(prefix + pxToDpStr("folderCellHeightPx", folderCellHeightPx));
writer.println(prefix + pxToDpStr("folderChildIconSizePx", folderChildIconSizePx));
@@ -1806,7 +1821,7 @@
* Set the viewScaleProvider for the builder
*
* @param viewScaleProvider The viewScaleProvider to be set for the
- * DeviceProfile
+ * DeviceProfile
* @return This builder
*/
@NonNull
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 3504b24..c16b319 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -20,7 +20,6 @@
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.Nullable;
@@ -53,18 +52,9 @@
super(context, attrs, defStyleAttr);
}
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mScrollbar == null || !mScrollbar.hasRecyclerView()) {
- bindFastScrollbar();
- }
- }
-
- public void bindFastScrollbar() {
- ViewGroup parent = (ViewGroup) getParent().getParent();
- mScrollbar = parent.findViewById(R.id.fast_scroller);
- mScrollbar.setRecyclerView(this, parent.findViewById(R.id.fast_scroller_popup));
+ public void bindFastScrollbar(RecyclerViewFastScroller scrollbar) {
+ mScrollbar = scrollbar;
+ mScrollbar.setRecyclerView(this);
onUpdateScrollbar(0);
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index bf492a9..03afba1 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -27,10 +27,6 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import androidx.annotation.Nullable;
-
-import java.util.function.Consumer;
-
/**
* View class that represents the bottom row of the home screen.
*/
@@ -43,8 +39,6 @@
private boolean mHasVerticalHotseat;
private Workspace<?> mWorkspace;
private boolean mSendTouchToWorkspace;
- @Nullable
- private Consumer<Boolean> mOnVisibilityAggregatedCallback;
private final View mQsb;
@@ -151,20 +145,6 @@
}
@Override
- public void onVisibilityAggregated(boolean isVisible) {
- super.onVisibilityAggregated(isVisible);
-
- if (mOnVisibilityAggregatedCallback != null) {
- mOnVisibilityAggregatedCallback.accept(isVisible);
- }
- }
-
- /** Sets a callback to be called onVisibilityAggregated */
- public void setOnVisibilityAggregatedCallback(@Nullable Consumer<Boolean> callback) {
- mOnVisibilityAggregatedCallback = callback;
- }
-
- @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index d97eac9..a498323 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -16,8 +16,8 @@
package com.android.launcher3;
+import static com.android.launcher3.LauncherPrefs.GRID_NAME;
import static com.android.launcher3.Utilities.dpiFromPx;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_DEVICE_PROFILE_LOGGING;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
@@ -59,6 +59,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Themes;
@@ -69,8 +70,6 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -93,8 +92,6 @@
public static final int TYPE_MULTI_DISPLAY = 1;
public static final int TYPE_TABLET = 2;
- private static final String KEY_IDP_GRID_NAME = "idp_grid_name";
-
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
// Constants that affects the interpolation curve between statically defined device profile
@@ -175,6 +172,7 @@
*/
public int numAllAppsColumns;
public int numDatabaseAllAppsColumns;
+ public @StyleRes int allAppsStyle;
/**
* Do not query directly. see {@link DeviceProfile#isScalableGrid}.
@@ -206,10 +204,11 @@
String gridName = getCurrentGridName(context);
String newGridName = initGrid(context, gridName);
if (!newGridName.equals(gridName)) {
- LauncherPrefs.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName)
- .apply();
+ LauncherPrefs.get(context).put(GRID_NAME, newGridName);
}
- new DeviceGridState(this).writeToPrefs(context);
+ LockedUserState.get(context).runOnUserUnlocked(() -> {
+ new DeviceGridState(this).writeToPrefs(context);
+ });
DisplayController.INSTANCE.get(context).setPriorityListener(
(displayContext, info, flags) -> {
@@ -315,7 +314,7 @@
}
public static String getCurrentGridName(Context context) {
- return LauncherPrefs.getPrefs(context).getString(KEY_IDP_GRID_NAME, null);
+ return LauncherPrefs.get(context).get(GRID_NAME);
}
private String initGrid(Context context, String gridName) {
@@ -384,6 +383,8 @@
hotseatBarBottomSpace = displayOption.hotseatBarBottomSpace;
hotseatQsbSpace = displayOption.hotseatQsbSpace;
+ allAppsStyle = closestProfile.allAppsStyle;
+
numAllAppsColumns = closestProfile.numAllAppsColumns;
numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
@@ -455,9 +456,8 @@
public void setCurrentGrid(Context context, String gridName) {
- Context appContext = context.getApplicationContext();
- LauncherPrefs.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply();
- MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext));
+ LauncherPrefs.get(context).put(GRID_NAME, gridName);
+ MAIN_EXECUTOR.execute(() -> onConfigChanged(context.getApplicationContext()));
}
private Object[] toModelState() {
@@ -680,18 +680,6 @@
float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density;
int rotation = WindowManagerProxy.INSTANCE.get(context).getRotation(context);
- if (Utilities.IS_DEBUG_DEVICE && ENABLE_DEVICE_PROFILE_LOGGING.get()) {
- StringWriter stringWriter = new StringWriter();
- PrintWriter printWriter = new PrintWriter(stringWriter);
- DisplayController.INSTANCE.get(context).dump(printWriter);
- printWriter.flush();
- Log.d("b/253338238", "getDeviceProfile -"
- + "\nconfig: " + config
- + "\ndisplayMetrics: " + res.getDisplayMetrics()
- + "\nrotation: " + rotation
- + "\n" + stringWriter,
- new Exception());
- }
return getBestMatch(screenWidth, screenHeight, rotation);
}
@@ -789,6 +777,7 @@
private final @StyleRes int folderStyle;
private final @StyleRes int cellStyle;
+ private final @StyleRes int allAppsStyle;
private final int numAllAppsColumns;
private final int numDatabaseAllAppsColumns;
private final int numHotseatIcons;
@@ -824,6 +813,8 @@
demoModeLayoutId = a.getResourceId(
R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId);
+ allAppsStyle = a.getResourceId(R.styleable.GridDisplayOption_allAppsStyle,
+ R.style.AllAppsStyleDefault);
numAllAppsColumns = a.getInt(
R.styleable.GridDisplayOption_numAllAppsColumns, numColumns);
numDatabaseAllAppsColumns = a.getInt(
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 41632f7..de60d05 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -19,7 +19,6 @@
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
@@ -86,7 +85,6 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -117,7 +115,6 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
-import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.CallSuper;
@@ -151,7 +148,6 @@
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderGridOrganizer;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logger.LauncherAtom;
@@ -306,8 +302,6 @@
private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@Thunk @VisibleForTesting public static final int NEW_APPS_ANIMATION_DELAY = 500;
- private static final int THEME_CROSS_FADE_ANIMATION_DURATION = 375;
-
private static final String DISPLAY_WORKSPACE_TRACE_METHOD_NAME = "DisplayWorkspaceFirstFrame";
private static final String DISPLAY_ALL_APPS_TRACE_METHOD_NAME = "DisplayAllApps";
public static final int DISPLAY_WORKSPACE_TRACE_COOKIE = 0;
@@ -504,7 +498,6 @@
mAppWidgetHolder.startListening();
setupViews();
- crossFadeWithPreviousAppearance();
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this);
@@ -1579,16 +1572,6 @@
public Object onRetainNonConfigurationInstance() {
NonConfigInstance instance = new NonConfigInstance();
instance.config = new Configuration(mOldConfig);
-
- int width = mDragLayer.getWidth();
- int height = mDragLayer.getHeight();
-
- if (FeatureFlags.ENABLE_LAUNCHER_ACTIVITY_THEME_CROSSFADE.get()
- && width > 0
- && height > 0) {
- instance.snapshot =
- BitmapRenderer.createHardwareBitmap(width, height, mDragLayer::draw);
- }
return instance;
}
@@ -1877,6 +1860,9 @@
}
private void setWorkspaceLoading(boolean value) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "running: setWorkspaceLoading=" + value);
+ }
mWorkspaceLoading = value;
}
@@ -1947,7 +1933,7 @@
Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(info.componentName);
setWaitingForResult(PendingRequestArgs.forIntent(REQUEST_CREATE_SHORTCUT, intent, info));
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: processShortcutFromDrop");
- if (!info.activityInfo.startConfigActivity(this, REQUEST_CREATE_SHORTCUT)) {
+ if (!info.getActivityInfo(this).startConfigActivity(this, REQUEST_CREATE_SHORTCUT)) {
handleActivityResult(REQUEST_CREATE_SHORTCUT, RESULT_CANCELED, null);
}
}
@@ -2323,6 +2309,9 @@
*/
public void startBinding() {
Object traceToken = TraceHelper.INSTANCE.beginSection("startBinding");
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "running: startBinding");
+ }
// Floating panels (except the full widget sheet) are associated with individual icons. If
// we are starting a fresh bind, close all such panels as all the icons are about
// to go away.
@@ -2795,6 +2784,9 @@
*/
public void finishBindingItems(IntSet pagesBoundFirst) {
Object traceToken = TraceHelper.INSTANCE.beginSection("finishBindingItems");
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "running: finishBindingItems");
+ }
mWorkspace.restoreInstanceStateForRemainingPages();
setWorkspaceLoading(false);
@@ -3211,7 +3203,7 @@
}
@Override
- public boolean shouldUseColorExtractionForPopup() {
+ public boolean canUseMultipleShadesForPopup() {
return getTopOpenViewWithType(this, TYPE_FOLDER) == null
&& getStateManager().getState() != LauncherState.ALL_APPS;
}
@@ -3285,41 +3277,6 @@
return (T) activityContext;
}
- /**
- * Cross-fades the launcher's updated appearance with its previous appearance.
- *
- * This method is used to cross-fade UI updates on activity creation, specifically dark mode
- * updates.
- */
- private void crossFadeWithPreviousAppearance() {
- NonConfigInstance lastInstance = (NonConfigInstance) getLastNonConfigurationInstance();
-
- if (lastInstance == null || lastInstance.snapshot == null) {
- return;
- }
-
- ImageView crossFadeHelper = new ImageView(this);
- crossFadeHelper.setImageBitmap(lastInstance.snapshot);
- crossFadeHelper.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
-
- InsettableFrameLayout.LayoutParams layoutParams = new InsettableFrameLayout.LayoutParams(
- InsettableFrameLayout.LayoutParams.MATCH_PARENT,
- InsettableFrameLayout.LayoutParams.MATCH_PARENT);
-
- layoutParams.ignoreInsets = true;
-
- crossFadeHelper.setLayoutParams(layoutParams);
-
- getRootView().addView(crossFadeHelper);
-
- crossFadeHelper
- .animate()
- .setDuration(THEME_CROSS_FADE_ANIMATION_DURATION)
- .alpha(0f)
- .withEndAction(() -> getRootView().removeView(crossFadeHelper))
- .start();
- }
-
public boolean supportsAdaptiveIconAnimation(View clickedView) {
return false;
}
@@ -3351,7 +3308,6 @@
private static class NonConfigInstance {
public Configuration config;
- public Bitmap snapshot;
}
@Override
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 2b98d98..c81ad01 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -44,6 +44,7 @@
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.InstallSessionTracker;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
@@ -106,25 +107,27 @@
}
mOnTerminateCallback.add(() -> mContext.unregisterReceiver(modelChangeReceiver));
- CustomWidgetManager.INSTANCE.get(mContext)
- .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
-
SafeCloseable userChangeListener = UserCache.INSTANCE.get(mContext)
.addUserChangeListener(mModel::forceReload);
mOnTerminateCallback.add(userChangeListener::close);
- IconObserver observer = new IconObserver();
- SafeCloseable iconChangeTracker = mIconProvider.registerIconChangeListener(
- observer, MODEL_EXECUTOR.getHandler());
- mOnTerminateCallback.add(iconChangeTracker::close);
- MODEL_EXECUTOR.execute(observer::verifyIconChanged);
- LauncherPrefs.get(context).addListener(observer, THEMED_ICONS);
- mOnTerminateCallback.add(
- () -> LauncherPrefs.get(mContext).removeListener(observer, THEMED_ICONS));
+ LockedUserState.get(context).runOnUserUnlocked(() -> {
+ CustomWidgetManager.INSTANCE.get(mContext)
+ .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
- InstallSessionTracker installSessionTracker =
- InstallSessionHelper.INSTANCE.get(context).registerInstallTracker(mModel);
- mOnTerminateCallback.add(installSessionTracker::unregister);
+ IconObserver observer = new IconObserver();
+ SafeCloseable iconChangeTracker = mIconProvider.registerIconChangeListener(
+ observer, MODEL_EXECUTOR.getHandler());
+ mOnTerminateCallback.add(iconChangeTracker::close);
+ MODEL_EXECUTOR.execute(observer::verifyIconChanged);
+ LauncherPrefs.get(context).addListener(observer, THEMED_ICONS);
+ mOnTerminateCallback.add(
+ () -> LauncherPrefs.get(mContext).removeListener(observer, THEMED_ICONS));
+
+ InstallSessionTracker installSessionTracker =
+ InstallSessionHelper.INSTANCE.get(context).registerInstallTracker(mModel);
+ mOnTerminateCallback.add(installSessionTracker::unregister);
+ });
// Register an observer to rebind the notification listener when dots are re-enabled.
SettingsCache settingsCache = SettingsCache.INSTANCE.get(mContext);
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 2e07e30..e675add 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -1,9 +1,28 @@
+/*
+ * 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
import android.content.Context
+import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
+import android.util.Log
import androidx.annotation.VisibleForTesting
+import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
+import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
import com.android.launcher3.allapps.WorkProfileManager
import com.android.launcher3.model.DeviceGridState
import com.android.launcher3.pm.InstallSessionHelper
@@ -15,16 +34,40 @@
/**
* Use same context for shared preferences, so that we use a single cached instance
+ *
* TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods.
*/
-class LauncherPrefs(private val context: Context) {
+class LauncherPrefs(private val encryptedContext: Context) {
+ private val deviceProtectedStorageContext =
+ encryptedContext.createDeviceProtectedStorageContext()
+
+ private val bootAwarePrefs
+ get() =
+ deviceProtectedStorageContext.getSharedPreferences(BOOT_AWARE_PREFS_KEY, MODE_PRIVATE)
+
+ private val Item.encryptedPrefs
+ get() = encryptedContext.getSharedPreferences(sharedPrefFile, MODE_PRIVATE)
+
+ // This call to `SharedPreferences` needs to be explicit rather than using `get` since doing so
+ // would result in a circular dependency between `isStartupDataMigrated` and `choosePreferences`
+ val isStartupDataMigrated: Boolean
+ get() =
+ bootAwarePrefs.getBoolean(
+ IS_STARTUP_DATA_MIGRATED.sharedPrefKey,
+ IS_STARTUP_DATA_MIGRATED.defaultValue
+ )
+
+ private fun chooseSharedPreferences(item: Item): SharedPreferences =
+ if (isBootAwareStartupDataEnabled && item.isBootAware && isStartupDataMigrated)
+ bootAwarePrefs
+ else item.encryptedPrefs
/** Wrapper around `getInner` for a `ContextualItem` */
- fun <T : Any> get(item: ContextualItem<T>): T =
- getInner(item, item.defaultValueFromContext(context))
+ fun <T> get(item: ContextualItem<T>): T =
+ getInner(item, item.defaultValueFromContext(encryptedContext))
/** Wrapper around `getInner` for an `Item` */
- fun <T : Any> get(item: ConstantItem<T>): T = getInner(item, item.defaultValue)
+ fun <T> get(item: ConstantItem<T>): T = getInner(item, item.defaultValue)
/**
* Retrieves the value for an [Item] from [SharedPreferences]. It handles method typing via the
@@ -32,11 +75,11 @@
* `String`, `Boolean`, `Float`, `Int`, `Long`, or `Set<String>`.
*/
@Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
- private fun <T : Any> getInner(item: Item, default: T): T {
- val sp = context.getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE)
+ private fun <T> getInner(item: Item, default: T): T {
+ val sp = chooseSharedPreferences(item)
- return when (default::class.java) {
- String::class.java -> sp.getString(item.sharedPrefKey, default as String)
+ return when (item.type) {
+ String::class.java -> sp.getString(item.sharedPrefKey, default as? String)
Boolean::class.java,
java.lang.Boolean::class.java -> sp.getBoolean(item.sharedPrefKey, default as Boolean)
Int::class.java,
@@ -45,11 +88,10 @@
java.lang.Float::class.java -> sp.getFloat(item.sharedPrefKey, default as Float)
Long::class.java,
java.lang.Long::class.java -> sp.getLong(item.sharedPrefKey, default as Long)
- Set::class.java -> sp.getStringSet(item.sharedPrefKey, default as Set<String>)
+ Set::class.java -> sp.getStringSet(item.sharedPrefKey, default as? Set<String>)
else ->
throw IllegalArgumentException(
- "item type: ${default::class.java}" +
- " is not compatible with sharedPref methods"
+ "item type: ${item.type}" + " is not compatible with sharedPref methods"
)
}
as T
@@ -67,16 +109,8 @@
fun put(vararg itemsToValues: Pair<Item, Any>): Unit =
prepareToPutValues(itemsToValues).forEach { it.apply() }
- /**
- * Stores the value provided in `SharedPreferences` according to the item configuration provided
- * It is asynchronous, so the caller can't assume that the value put is immediately available.
- */
- fun <T : Any> put(item: Item, value: T): Unit =
- context
- .getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE)
- .edit()
- .putValue(item, value)
- .apply()
+ /** See referenced `put` method above. */
+ fun <T : Any> put(item: Item, value: T): Unit = put(item.to(value))
/**
* Synchronously stores all the values provided according to their associated Item
@@ -86,27 +120,35 @@
prepareToPutValues(itemsToValues).forEach { it.commit() }
/**
- * Update each shared preference file with the item - value pairs provided. This method is
- * optimized to avoid retrieving the same shared preference file multiple times.
+ * Updates the values stored in `SharedPreferences` for each corresponding Item-value pair. If
+ * the item is boot aware, this method updates both the boot aware and the encrypted files. This
+ * is done because: 1) It allows for easy roll-back if the data is already in encrypted prefs
+ * and we need to turn off the boot aware data feature & 2) It simplifies Backup/Restore, which
+ * already points to encrypted storage.
*
- * @return `List<SharedPreferences.Editor>` 1 for each distinct shared preference file among the
- * items given as part of the itemsToValues parameter
+ * Returns a list of editors with all transactions added so that the caller can determine to use
+ * .apply() or .commit()
*/
private fun prepareToPutValues(
- itemsToValues: Array<out Pair<Item, Any>>
- ): List<SharedPreferences.Editor> =
- itemsToValues
- .groupBy { it.first.sharedPrefFile }
- .map { fileToItemValueList ->
- context
- .getSharedPreferences(fileToItemValueList.key, Context.MODE_PRIVATE)
- .edit()
- .apply {
- fileToItemValueList.value.forEach { itemToValue ->
- putValue(itemToValue.first, itemToValue.second)
- }
- }
+ updates: Array<out Pair<Item, Any>>
+ ): List<SharedPreferences.Editor> {
+ val updatesPerPrefFile = updates.groupBy { it.first.encryptedPrefs }.toMutableMap()
+
+ if (isBootAwareStartupDataEnabled) {
+ val bootAwareUpdates = updates.filter { it.first.isBootAware }
+ if (bootAwareUpdates.isNotEmpty()) {
+ updatesPerPrefFile[bootAwarePrefs] = bootAwareUpdates
}
+ }
+
+ return updatesPerPrefFile.map { prefToItemValueList ->
+ prefToItemValueList.key.edit().apply {
+ prefToItemValueList.value.forEach { itemToValue: Pair<Item, Any> ->
+ putValue(itemToValue.first, itemToValue.second)
+ }
+ }
+ }
+ }
/**
* Handles adding values to `SharedPreferences` regardless of type. This method is especially
@@ -116,10 +158,10 @@
@Suppress("UNCHECKED_CAST")
private fun SharedPreferences.Editor.putValue(
item: Item,
- value: Any
+ value: Any?
): SharedPreferences.Editor =
- when (value::class.java) {
- String::class.java -> putString(item.sharedPrefKey, value as String)
+ when (item.type) {
+ String::class.java -> putString(item.sharedPrefKey, value as? String)
Boolean::class.java,
java.lang.Boolean::class.java -> putBoolean(item.sharedPrefKey, value as Boolean)
Int::class.java,
@@ -128,10 +170,10 @@
java.lang.Float::class.java -> putFloat(item.sharedPrefKey, value as Float)
Long::class.java,
java.lang.Long::class.java -> putLong(item.sharedPrefKey, value as Long)
- Set::class.java -> putStringSet(item.sharedPrefKey, value as Set<String>)
+ Set::class.java -> putStringSet(item.sharedPrefKey, value as? Set<String>)
else ->
throw IllegalArgumentException(
- "item type: ${value::class} is not compatible with sharedPref methods"
+ "item type: ${item.type} is not compatible with sharedPref methods"
)
}
@@ -142,13 +184,9 @@
*/
fun addListener(listener: OnSharedPreferenceChangeListener, vararg items: Item) {
items
- .map { it.sharedPrefFile }
+ .map { chooseSharedPreferences(it) }
.distinct()
- .forEach {
- context
- .getSharedPreferences(it, Context.MODE_PRIVATE)
- .registerOnSharedPreferenceChangeListener(listener)
- }
+ .forEach { it.registerOnSharedPreferenceChangeListener(listener) }
}
/**
@@ -158,13 +196,9 @@
fun removeListener(listener: OnSharedPreferenceChangeListener, vararg items: Item) {
// If a listener is not registered to a SharedPreference, unregistering it does nothing
items
- .map { it.sharedPrefFile }
+ .map { chooseSharedPreferences(it) }
.distinct()
- .forEach {
- context
- .getSharedPreferences(it, Context.MODE_PRIVATE)
- .unregisterOnSharedPreferenceChangeListener(listener)
- }
+ .forEach { it.unregisterOnSharedPreferenceChangeListener(listener) }
}
/**
@@ -173,10 +207,8 @@
*/
fun has(vararg items: Item): Boolean {
items
- .groupBy { it.sharedPrefFile }
- .forEach { (file, itemsSublist) ->
- val prefs: SharedPreferences =
- context.getSharedPreferences(file, Context.MODE_PRIVATE)
+ .groupBy { chooseSharedPreferences(it) }
+ .forEach { (prefs, itemsSublist) ->
if (!itemsSublist.none { !prefs.contains(it.sharedPrefKey) }) return false
}
return true
@@ -191,73 +223,136 @@
fun removeSync(vararg items: Item) = prepareToRemove(items).forEach { it.commit() }
/**
- * Creates `SharedPreferences.Editor` transactions for removing all the provided [Item] values
- * from their respective `SharedPreferences` files. These returned `Editors` can then be
- * committed or applied for synchronous or async behavior.
+ * Removes the key value pairs stored in `SharedPreferences` for each corresponding Item. If the
+ * item is boot aware, this method removes the data from both the boot aware and encrypted
+ * files.
+ *
+ * @return a list of editors with all transactions added so that the caller can determine to use
+ * .apply() or .commit()
*/
- private fun prepareToRemove(items: Array<out Item>): List<SharedPreferences.Editor> =
- items
- .groupBy { it.sharedPrefFile }
- .map { (file, items) ->
- context.getSharedPreferences(file, Context.MODE_PRIVATE).edit().also { editor ->
- items.forEach { item -> editor.remove(item.sharedPrefKey) }
- }
+ private fun prepareToRemove(items: Array<out Item>): List<SharedPreferences.Editor> {
+ val itemsPerFile = items.groupBy { it.encryptedPrefs }.toMutableMap()
+
+ if (isBootAwareStartupDataEnabled) {
+ val bootAwareUpdates = items.filter { it.isBootAware }
+ if (bootAwareUpdates.isNotEmpty()) {
+ itemsPerFile[bootAwarePrefs] = bootAwareUpdates
}
+ }
+
+ return itemsPerFile.map { (prefs, items) ->
+ prefs.edit().also { editor ->
+ items.forEach { item -> editor.remove(item.sharedPrefKey) }
+ }
+ }
+ }
+
+ fun migrateStartupDataToDeviceProtectedStorage() {
+ if (!isBootAwareStartupDataEnabled) return
+
+ Log.d(
+ TAG,
+ "Migrating data to unencrypted shared preferences to enable preloading " +
+ "while the user is locked the next time the device reboots."
+ )
+
+ with(bootAwarePrefs.edit()) {
+ BOOT_AWARE_ITEMS.forEach { putValue(it, get(it)) }
+ putBoolean(IS_STARTUP_DATA_MIGRATED.sharedPrefKey, true)
+ apply()
+ }
+ }
companion object {
+ private const val TAG = "LauncherPrefs"
+ @VisibleForTesting const val BOOT_AWARE_PREFS_KEY = "boot_aware_prefs"
+
@JvmField var INSTANCE = MainThreadInitializedObject { LauncherPrefs(it) }
@JvmStatic fun get(context: Context): LauncherPrefs = INSTANCE.get(context)
- @JvmField val ICON_STATE = nonRestorableItem(LauncherAppState.KEY_ICON_STATE, "")
- @JvmField val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false)
+ @JvmField val ICON_STATE = nonRestorableItem(LauncherAppState.KEY_ICON_STATE, "", true)
+ @JvmField val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, true)
@JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
@JvmField val WORK_EDU_STEP = backedUpItem(WorkProfileManager.KEY_WORK_EDU_STEP, 0)
- @JvmField val WORKSPACE_SIZE = backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "")
- @JvmField val HOTSEAT_COUNT = backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1)
+ @JvmField val WORKSPACE_SIZE = backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "", true)
+ @JvmField val HOTSEAT_COUNT = backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1, true)
@JvmField
val DEVICE_TYPE =
- backedUpItem(DeviceGridState.KEY_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE)
- @JvmField val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "")
+ backedUpItem(DeviceGridState.KEY_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE, true)
+ @JvmField val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "", true)
@JvmField
val RESTORE_DEVICE =
- backedUpItem(RestoreDbTask.RESTORED_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE)
+ backedUpItem(
+ RestoreDbTask.RESTORED_DEVICE_TYPE,
+ InvariantDeviceProfile.TYPE_PHONE,
+ true
+ )
@JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
@JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
@JvmField
+ val GRID_NAME =
+ ConstantItem(
+ "idp_grid_name",
+ isBackedUp = true,
+ defaultValue = null,
+ isBootAware = true,
+ type = String::class.java
+ )
+ @JvmField
val ALLOW_ROTATION =
- backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY) {
+ backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY, Boolean::class.java) {
RotationHelper.getAllowRotationDefaultValue(DisplayController.INSTANCE.get(it).info)
}
-
- @VisibleForTesting
- @JvmStatic
- fun <T> backedUpItem(sharedPrefKey: String, defaultValue: T): ConstantItem<T> =
- ConstantItem(sharedPrefKey, LauncherFiles.SHARED_PREFERENCES_KEY, defaultValue)
-
- @JvmStatic
- fun <T> backedUpItem(
- sharedPrefKey: String,
- defaultValueFromContext: (c: Context) -> T
- ): ContextualItem<T> =
- ContextualItem(
- sharedPrefKey,
- LauncherFiles.SHARED_PREFERENCES_KEY,
- defaultValueFromContext
+ @JvmField
+ val IS_STARTUP_DATA_MIGRATED =
+ ConstantItem(
+ "is_startup_data_boot_aware",
+ isBackedUp = false,
+ defaultValue = false,
+ isBootAware = true
)
@VisibleForTesting
@JvmStatic
- fun <T> nonRestorableItem(sharedPrefKey: String, defaultValue: T): ConstantItem<T> =
- ConstantItem(sharedPrefKey, LauncherFiles.DEVICE_PREFERENCES_KEY, defaultValue)
+ fun <T> backedUpItem(
+ sharedPrefKey: String,
+ defaultValue: T,
+ isBootAware: Boolean = false
+ ): ConstantItem<T> =
+ ConstantItem(sharedPrefKey, isBackedUp = true, defaultValue, isBootAware)
+
+ @JvmStatic
+ fun <T> backedUpItem(
+ sharedPrefKey: String,
+ type: Class<out T>,
+ isBootAware: Boolean = false,
+ defaultValueFromContext: (c: Context) -> T
+ ): ContextualItem<T> =
+ ContextualItem(
+ sharedPrefKey,
+ isBackedUp = true,
+ defaultValueFromContext,
+ isBootAware,
+ type
+ )
+
+ @VisibleForTesting
+ @JvmStatic
+ fun <T> nonRestorableItem(
+ sharedPrefKey: String,
+ defaultValue: T,
+ isBootAware: Boolean = false
+ ): ConstantItem<T> =
+ ConstantItem(sharedPrefKey, isBackedUp = false, defaultValue, isBootAware)
@Deprecated("Don't use shared preferences directly. Use other LauncherPref methods.")
@JvmStatic
fun getPrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so we use single cached instance
return context.applicationContext.getSharedPreferences(
- LauncherFiles.SHARED_PREFERENCES_KEY,
- Context.MODE_PRIVATE
+ SHARED_PREFERENCES_KEY,
+ MODE_PRIVATE
)
}
@@ -266,30 +361,51 @@
fun getDevicePrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so we use a single cached instance
return context.applicationContext.getSharedPreferences(
- LauncherFiles.DEVICE_PREFERENCES_KEY,
- Context.MODE_PRIVATE
+ DEVICE_PREFERENCES_KEY,
+ MODE_PRIVATE
)
}
}
}
+// This is hard-coded to false for now until it is time to release this optimization. It is only
+// a var because the unit tests are setting this to true so they can run.
+@VisibleForTesting var isBootAwareStartupDataEnabled: Boolean = false
+
+private val BOOT_AWARE_ITEMS: MutableSet<ConstantItem<*>> = mutableSetOf()
+
abstract class Item {
abstract val sharedPrefKey: String
- abstract val sharedPrefFile: String
+ abstract val isBackedUp: Boolean
+ abstract val type: Class<*>
+ abstract val isBootAware: Boolean
+ val sharedPrefFile: String
+ get() = if (isBackedUp) SHARED_PREFERENCES_KEY else DEVICE_PREFERENCES_KEY
fun <T> to(value: T): Pair<Item, T> = Pair(this, value)
}
data class ConstantItem<T>(
override val sharedPrefKey: String,
- override val sharedPrefFile: String,
- val defaultValue: T
-) : Item()
+ override val isBackedUp: Boolean,
+ val defaultValue: T,
+ override val isBootAware: Boolean,
+ // The default value can be null. If so, the type needs to be explicitly stated, or else NPE
+ override val type: Class<out T> = defaultValue!!::class.java
+) : Item() {
+ init {
+ if (isBootAware && isBootAwareStartupDataEnabled) {
+ BOOT_AWARE_ITEMS.add(this)
+ }
+ }
+}
data class ContextualItem<T>(
override val sharedPrefKey: String,
- override val sharedPrefFile: String,
- private val defaultSupplier: (c: Context) -> T
+ override val isBackedUp: Boolean,
+ private val defaultSupplier: (c: Context) -> T,
+ override val isBootAware: Boolean,
+ override val type: Class<out T>
) : Item() {
private var default: T? = null
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 81fbe79..b8d13ed 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -226,6 +226,20 @@
}
/**
+ * Returns whether taskbar global drag is disallowed in this state.
+ */
+ public boolean disallowTaskbarGlobalDrag() {
+ return false;
+ }
+
+ /**
+ * Returns whether the taskbar shortcut should trigger split selection mode.
+ */
+ public boolean allowTaskbarInitialSplitSelection() {
+ return false;
+ }
+
+ /**
* Fraction shift in the vertical translation UI and related properties
*
* @see com.android.launcher3.allapps.AllAppsTransitionController
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index f2a3de7..3d7e11e 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -18,7 +18,6 @@
import android.content.Context;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.BitmapCreationCheck;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.logging.FileLog;
@@ -37,7 +36,6 @@
protected void init(Context context) {
FileLog.setDir(context.getApplicationContext().getFilesDir());
- FeatureFlags.initialize(context);
IconShape.init(context);
if (BitmapCreationCheck.ENABLED) {
diff --git a/src/com/android/launcher3/MultipageCellLayout.java b/src/com/android/launcher3/MultipageCellLayout.java
index d671c7d..6a518a7 100644
--- a/src/com/android/launcher3/MultipageCellLayout.java
+++ b/src/com/android/launcher3/MultipageCellLayout.java
@@ -38,6 +38,8 @@
private View mSeam;
+ private boolean mSeamWasAdded = false;
+
public MultipageCellLayout(Context context) {
this(context, null);
}
@@ -65,44 +67,68 @@
}
@Override
+ boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, View dragView,
+ int[] direction, boolean commit) {
+ // Add seam to x position
+ if (cellX >= mCountX / 2) {
+ cellX++;
+ }
+ int finalCellX = cellX;
+ return simulateSeam(
+ () -> super.createAreaForResize(finalCellX, cellY, spanX, spanY, dragView,
+ direction, commit));
+ }
+
+ @Override
ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY, int minSpanX, int minSpanY,
int spanX, int spanY) {
- return simulateSeam(
+ return removeSeamFromSolution(simulateSeam(
() -> super.closestEmptySpaceReorder(pixelX, pixelY, minSpanX, minSpanY, spanX,
- spanY));
+ spanY)));
}
@Override
protected ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX,
int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
ItemConfiguration solution) {
- return simulateSeam(
+ return removeSeamFromSolution(simulateSeam(
() -> super.findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
- direction, dragView, decX, solution));
+ direction, dragView, decX, solution)));
}
@Override
public ItemConfiguration dropInPlaceSolution(int pixelX, int pixelY, int spanX, int spanY,
View dragView) {
- return simulateSeam(
- () -> super.dropInPlaceSolution(pixelX, pixelY, spanX, spanY, dragView));
+ return removeSeamFromSolution(simulateSeam(
+ () -> super.dropInPlaceSolution(pixelX, pixelY, spanX, spanY, dragView)));
}
- protected ItemConfiguration simulateSeam(Supplier<ItemConfiguration> f) {
+ void addSeam() {
CellLayoutLayoutParams lp = new CellLayoutLayoutParams(mCountX / 2, 0, 1, mCountY);
+ mSeamWasAdded = true;
lp.canReorder = false;
mCountX++;
mShortcutsAndWidgets.addViewInLayout(mSeam, lp);
- GridOccupancy auxGrid = mOccupied;
- mOccupied = createGridOccupancy();
+ mOccupied = createGridOccupancyWithSeam(mOccupied);
mTmpOccupied = new GridOccupancy(mCountX, mCountY);
+ }
- ItemConfiguration res = removeSeamFromSolution(f.get());
-
+ void removeSeam() {
mCountX--;
mShortcutsAndWidgets.removeViewInLayout(mSeam);
- mOccupied = auxGrid;
mTmpOccupied = new GridOccupancy(mCountX, mCountY);
+ mSeamWasAdded = false;
+ }
+
+ protected <T> T simulateSeam(Supplier<T> f) {
+ if (mSeamWasAdded) {
+ return f.get();
+ }
+ GridOccupancy auxGrid = mOccupied;
+ addSeam();
+ T res = f.get();
+ removeSeam();
+ mOccupied = auxGrid;
return res;
}
@@ -113,14 +139,19 @@
return solution;
}
- GridOccupancy createGridOccupancy() {
- GridOccupancy grid = new GridOccupancy(mCountX, mCountY);
- for (int i = 0; i < mShortcutsAndWidgets.getChildCount(); i++) {
- View view = mShortcutsAndWidgets.getChildAt(i);
- CellLayoutLayoutParams lp = (CellLayoutLayoutParams) view.getLayoutParams();
- int seamOffset = lp.getCellX() >= mCountX / 2 && lp.canReorder ? 1 : 0;
- grid.markCells(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan, lp.cellVSpan,
- true);
+
+
+ GridOccupancy createGridOccupancyWithSeam(GridOccupancy gridOccupancy) {
+ GridOccupancy grid = new GridOccupancy(getCountX(), getCountY());
+ for (int x = 0; x < getCountX(); x++) {
+ for (int y = 0; y < getCountY(); y++) {
+ int offset = x >= getCountX() / 2 ? 1 : 0;
+ if (x == getCountX() / 2) {
+ grid.cells[x][y] = true;
+ } else {
+ grid.cells[x][y] = gridOccupancy.cells[x - offset][y];
+ }
+ }
}
return grid;
}
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index b7a22fc..000ddd8 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -21,7 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import java.util.Optional;
@@ -29,13 +29,20 @@
* Meta data that is used for deferred binding. e.g., this object is used to pass information on
* draggable targets when they are dropped onto the workspace from another container.
*/
-public class PendingAddItemInfo extends ItemInfo {
+public class PendingAddItemInfo extends ItemInfoWithIcon {
/**
* The component that will be created.
*/
public ComponentName componentName;
+ public PendingAddItemInfo() { }
+
+ public PendingAddItemInfo(PendingAddItemInfo info) {
+ super(info);
+ componentName = info.componentName;
+ }
+
@Override
protected String dumpProperties() {
return super.dumpProperties() + " componentName=" + componentName;
@@ -46,13 +53,18 @@
*/
@NonNull
@Override
- public ItemInfo makeShallowCopy() {
+ public PendingAddItemInfo makeShallowCopy() {
PendingAddItemInfo itemInfo = new PendingAddItemInfo();
itemInfo.copyFrom(this);
itemInfo.componentName = this.componentName;
return itemInfo;
}
+ @Override
+ public PendingAddItemInfo clone() {
+ return makeShallowCopy();
+ }
+
@Nullable
@Override
public ComponentName getTargetComponent() {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index bd9493b..7d01f7b 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -38,6 +38,7 @@
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
@@ -130,10 +131,10 @@
/**
* Indicates if the device has a debug build. Should only be used to store additional info or
* add extra logging and not for changing the app behavior.
+ * @deprecated Use {@link BuildConfig#IS_DEBUG_DEVICE} directly
*/
- public static final boolean IS_DEBUG_DEVICE =
- Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") ||
- Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
+ @Deprecated
+ public static final boolean IS_DEBUG_DEVICE = BuildConfig.IS_DEBUG_DEVICE;
/**
* Returns true if theme is dark.
@@ -343,6 +344,21 @@
}
/**
+ * Sets the x and y pivots for scaling from one Rect to another.
+ *
+ * @param src the source rectangle to scale from.
+ * @param dst the destination rectangle to scale to.
+ * @param outPivot the pivots set for scaling from src to dst.
+ */
+ public static void getPivotsForScalingRectToRect(Rect src, Rect dst, PointF outPivot) {
+ float pivotXPct = ((float) src.left - dst.left) / ((float) dst.width() - src.width());
+ outPivot.x = dst.left + dst.width() * pivotXPct;
+
+ float pivotYPct = ((float) src.top - dst.top) / ((float) dst.height() - src.height());
+ outPivot.y = dst.top + dst.height() * pivotYPct;
+ }
+
+ /**
* Maps t from one range to another range.
* @param t The value to map.
* @param fromMin The lower bound of the range that t is being mapped from.
@@ -557,6 +573,12 @@
int width, int height, Object[] outObj) {
ActivityContext activity = ActivityContext.lookupContext(context);
LauncherAppState appState = LauncherAppState.getInstance(context);
+ if (info instanceof PendingAddShortcutInfo) {
+ ShortcutConfigActivityInfo activityInfo =
+ ((PendingAddShortcutInfo) info).getActivityInfo(context);
+ outObj[0] = activityInfo;
+ return activityInfo.getFullResIcon(appState.getIconCache());
+ }
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
LauncherActivityInfo activityInfo = context.getSystemService(LauncherApps.class)
.resolveActivity(info.getIntent(), info.user);
@@ -565,12 +587,6 @@
.getIconProvider().getIcon(
activityInfo, activity.getDeviceProfile().inv.fillResIconDpi);
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- if (info instanceof PendingAddShortcutInfo) {
- ShortcutConfigActivityInfo activityInfo =
- ((PendingAddShortcutInfo) info).activityInfo;
- outObj[0] = activityInfo;
- return activityInfo.getFullResIcon(appState.getIconCache());
- }
List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
.buildRequest(context)
.query(ShortcutRequest.ALL);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fa54dcf..ba492d5 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -501,7 +501,7 @@
}
private boolean isTwoPanelEnabled() {
- return mLauncher.mDeviceProfile.isTwoPanels;
+ return !FOLDABLE_SINGLE_PAGE.get() && mLauncher.mDeviceProfile.isTwoPanels;
}
@Override
@@ -663,8 +663,9 @@
// Inflate the cell layout, but do not add it automatically so that we can get the newly
// created CellLayout.
+ DeviceProfile dp = mLauncher.getDeviceProfile();
CellLayout newScreen;
- if (FOLDABLE_SINGLE_PAGE.get() && isTwoPanelEnabled()) {
+ if (FOLDABLE_SINGLE_PAGE.get() && dp.isTwoPanels) {
newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen_foldable, this, false /* attachToRoot */);
} else {
@@ -2689,7 +2690,7 @@
private void onDropExternal(final int[] touchXY, final CellLayout cellLayout, DragObject d) {
if (d.dragInfo instanceof PendingAddShortcutInfo) {
WorkspaceItemInfo si = ((PendingAddShortcutInfo) d.dragInfo)
- .activityInfo.createWorkspaceItemInfo();
+ .getActivityInfo(mLauncher).createWorkspaceItemInfo();
if (si != null) {
d.dragInfo = si;
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index c3d24f9..8fbe997 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -16,10 +16,10 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
-import static com.android.launcher3.allapps.AllAppsTransitionController.SWIPE_ALL_APPS_TO_HOME_MIN_SCALE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
+import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -134,6 +134,8 @@
protected AllAppsPagedView mViewPager;
protected FloatingHeaderView mHeader;
protected View mBottomSheetBackground;
+ protected RecyclerViewFastScroller mFastScroller;
+
/**
* View that defines the search box. Result is rendered inside {@link #mSearchRecyclerView}.
*/
@@ -219,6 +221,8 @@
mBottomSheetBackground = findViewById(R.id.bottom_sheet_background);
mBottomSheetHandleArea = findViewById(R.id.bottom_sheet_handle_area);
mSearchRecyclerView = findViewById(R.id.search_results_list_view);
+ mFastScroller = findViewById(R.id.fast_scroller);
+ mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
// Add the search box above everything else.
mSearchContainer = inflateSearchBox();
@@ -302,6 +306,7 @@
if (!mSearchTransitionController.isRunning() && goingToSearch == isSearching()) {
return;
}
+ mFastScroller.setVisibility(goingToSearch ? INVISIBLE : VISIBLE);
if (goingToSearch) {
// Fade out the button to pause work apps.
mWorkManager.onActivePageChanged(SEARCH);
@@ -360,6 +365,9 @@
mAH.get(i).mRecyclerView.scrollToTop();
}
}
+ if (mTouchHandler != null) {
+ mTouchHandler.endFastScrolling();
+ }
if (mHeader != null && mHeader.getVisibility() == VISIBLE) {
mHeader.reset(animate);
}
@@ -408,7 +416,7 @@
return;
}
if (mAH.get(currentActivePage).mRecyclerView != null) {
- mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
+ mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar(mFastScroller);
}
// Header keeps track of active recycler view to properly render header protection.
mHeader.setActiveRV(currentActivePage);
@@ -439,9 +447,11 @@
return;
}
- RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
- getSearchRecyclerView().removeItemDecoration(decoration);
- getSearchRecyclerView().addItemDecoration(decoration);
+ if (!FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) {
+ RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
+ getSearchRecyclerView().removeItemDecoration(decoration);
+ getSearchRecyclerView().addItemDecoration(decoration);
+ }
// replaceAppsRVcontainer() needs to use both mUsingTabs value to remove the old view AND
// showTabs value to create new view. Hence the mUsingTabs new value assignment MUST happen
@@ -489,7 +499,7 @@
if (isSearchBarOnBottom()) {
// Keep the scroller above the search bar.
RelativeLayout.LayoutParams scrollerLayoutParams =
- (LayoutParams) findViewById(R.id.fast_scroller).getLayoutParams();
+ (LayoutParams) mFastScroller.getLayoutParams();
scrollerLayoutParams.addRule(RelativeLayout.ABOVE, R.id.search_container_all_apps);
scrollerLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
scrollerLayoutParams.bottomMargin = getResources().getDimensionPixelSize(
@@ -524,7 +534,7 @@
public void getOutline(View view, Outline outline) {
@Px final int bottomOffsetPx =
(int) (ActivityAllAppsContainerView.this.getMeasuredHeight()
- * SWIPE_ALL_APPS_TO_HOME_MIN_SCALE);
+ * PREDICTIVE_BACK_MIN_SCALE);
outline.setRect(
0,
0,
@@ -1050,12 +1060,6 @@
: mViewPager == null ? AdapterHolder.MAIN : mViewPager.getNextPage();
}
- /** The scroll bar for the active apps recycler view. */
- public RecyclerViewFastScroller getScrollBar() {
- AllAppsRecyclerView rv = getActiveAppsRecyclerView();
- return rv == null ? null : rv.getScrollbar();
- }
-
/**
* Adds an update listener to animator that adds springs to the animation.
*/
@@ -1101,15 +1105,26 @@
@Override
public void drawOnScrimWithScale(Canvas canvas, float scale) {
- boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
+ final boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
+ final View panel = mBottomSheetBackground;
+ final float translationY = ((View) panel.getParent()).getTranslationY();
+ final float horizontalScaleOffset = (1 - scale) * panel.getWidth() / 2;
+ final float verticalScaleOffset = (1 - scale) * (panel.getHeight() - getHeight() / 2);
+
+ final float topNoScale = panel.getTop() + translationY;
+ final float topWithScale = topNoScale + verticalScaleOffset;
+ final float leftWithScale = panel.getLeft() + horizontalScaleOffset;
+ final float rightWithScale = panel.getRight() - horizontalScaleOffset;
// Draw full background panel for tablets.
if (isTablet) {
mHeaderPaint.setColor(mBottomSheetBackgroundColor);
- View panel = (View) mBottomSheetBackground;
- float translationY = ((View) panel.getParent()).getTranslationY();
- mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY,
- panel.getRight(), panel.getBottom());
+
+ mTmpRectF.set(
+ leftWithScale,
+ topWithScale,
+ rightWithScale,
+ panel.getBottom());
mTmpPath.reset();
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
canvas.drawPath(mTmpPath, mHeaderPaint);
@@ -1125,25 +1140,33 @@
if (mHeaderPaint.getColor() == mScrimColor || mHeaderPaint.getColor() == 0) {
return;
}
- final float offset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
- final float bottom =
- scale * (getHeaderBottom() + getVisibleContainerView().getPaddingTop()) + offset;
- FloatingHeaderView headerView = getFloatingHeaderView();
+
+ // Draw header on background panel
+ final float headerBottomNoScale =
+ getHeaderBottom() + getVisibleContainerView().getPaddingTop();
+ final float headerHeightNoScale = headerBottomNoScale - topNoScale;
+ final float headerBottomWithScaleOnTablet = topWithScale + headerHeightNoScale * scale;
+ final float headerBottomOffset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
+ final float headerBottomWithScaleOnPhone = headerBottomNoScale * scale + headerBottomOffset;
+ final FloatingHeaderView headerView = getFloatingHeaderView();
if (isTablet) {
// Start adding header protection if search bar or tabs will attach to the top.
- if (!isSearchBarOnBottom() || mUsingTabs) {
- View panel = (View) mBottomSheetBackground;
- float translationY = ((View) panel.getParent()).getTranslationY();
- mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY, panel.getRight(),
- bottom);
+ if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) {
+ mTmpRectF.set(
+ leftWithScale,
+ topWithScale,
+ rightWithScale,
+ headerBottomWithScaleOnTablet);
mTmpPath.reset();
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
canvas.drawPath(mTmpPath, mHeaderPaint);
}
} else {
- canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint);
+ canvas.drawRect(0, 0, canvas.getWidth(), headerBottomWithScaleOnPhone, mHeaderPaint);
}
- int tabsHeight = headerView.getPeripheralProtectionHeight();
+
+ // If tab exist (such as work profile), extend header with tab height
+ final int tabsHeight = headerView.getPeripheralProtectionHeight();
if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
if (DEBUG_HEADER_PROTECTION) {
mHeaderPaint.setColor(Color.BLUE);
@@ -1151,13 +1174,24 @@
} else {
mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
}
- int left = 0;
- int right = canvas.getWidth();
+ float left = 0f;
+ float right = canvas.getWidth();
if (isTablet) {
- left = mBottomSheetBackground.getLeft();
- right = mBottomSheetBackground.getRight();
+ left = mBottomSheetBackground.getLeft() + horizontalScaleOffset;
+ right = mBottomSheetBackground.getRight() - horizontalScaleOffset;
}
- canvas.drawRect(left, bottom, right, bottom + tabsHeight, mHeaderPaint);
+
+ final float tabTopWithScale = isTablet
+ ? headerBottomWithScaleOnTablet
+ : headerBottomWithScaleOnPhone;
+ final float tabBottomWithScale = tabTopWithScale + tabsHeight * scale;
+
+ canvas.drawRect(
+ left,
+ tabTopWithScale,
+ right,
+ tabBottomWithScale,
+ mHeaderPaint);
}
}
@@ -1217,6 +1251,7 @@
void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
mAppsList.updateItemFilter(matcher);
mRecyclerView = (AllAppsRecyclerView) rv;
+ mRecyclerView.bindFastScrollbar(mFastScroller);
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
mRecyclerView.setApps(mAppsList);
mRecyclerView.setLayoutManager(mLayoutManager);
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 866932a..df383bf 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -21,7 +21,6 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import androidx.annotation.Px;
import androidx.core.view.accessibility.AccessibilityEventCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
@@ -146,19 +145,6 @@
}
/**
- * We need to extend all apps' RecyclerView's bottom by 5% of view height to ensure extra
- * roll(s) of app icons is rendered at the bottom, so that they can fill the bottom gap
- * created during predictive back's scale animation from all apps to home.
- */
- @Override
- protected void calculateExtraLayoutSpace(RecyclerView.State state, int[] extraLayoutSpace) {
- super.calculateExtraLayoutSpace(state, extraLayoutSpace);
- @Px int extraSpacePx = (int) (getHeight()
- * (1 - AllAppsTransitionController.SWIPE_ALL_APPS_TO_HOME_MIN_SCALE) / 2);
- extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], extraSpacePx);
- }
-
- /**
* Returns the number of rows before {@param adapterPosition}, including this position
* which should not be counted towards the collection info.
*/
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 6b45fe6..7c5c003 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -43,7 +43,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.List;
@@ -274,10 +273,6 @@
: getRootWindowInsets().getSystemWindowInsetBottom();
}
- public RecyclerViewFastScroller getScrollbar() {
- return mScrollbar;
- }
-
@Override
public boolean hasOverlappingRendering() {
return false;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4a1c334..54bf6a8 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -32,6 +32,7 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.util.FloatProperty;
import android.view.HapticFeedbackConstants;
import android.view.View;
@@ -47,17 +48,22 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.ScrollableLayoutManager;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.ScrimView;
/**
@@ -74,10 +80,11 @@
implements StateHandler<LauncherState>, OnDeviceProfileChangeListener {
// This constant should match the second derivative of the animator interpolator.
public static final float INTERP_COEFF = 1.7f;
- public static final float SWIPE_ALL_APPS_TO_HOME_MIN_SCALE = 0.9f;
- private static final int REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS = 200;
+ public static final int REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS = 200;
private static final float NAV_BAR_COLOR_FORCE_UPDATE_THRESHOLD = 0.1f;
+ private static final float SWIPE_DRAG_COMMIT_THRESHOLD =
+ 1 - AllAppsSwipeController.ALL_APPS_STATE_TRANSITION_MANUAL;
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
@@ -181,6 +188,7 @@
private boolean mIsTablet;
private boolean mHasScaleEffect;
+ private final VibratorWrapper mVibratorWrapper;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
@@ -192,7 +200,9 @@
? FLAG_DARK_NAV : FLAG_LIGHT_NAV;
setShiftRange(dp.allAppsShiftRange);
+ mAllAppScale.value = 1;
mLauncher.addOnDeviceProfileChangeListener(this);
+ mVibratorWrapper = VibratorWrapper.INSTANCE.get(mLauncher.getApplicationContext());
}
public float getShiftRange() {
@@ -271,8 +281,9 @@
float deceleratedProgress =
Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(backProgress);
- float scaleProgress = SWIPE_ALL_APPS_TO_HOME_MIN_SCALE
- + (1 - SWIPE_ALL_APPS_TO_HOME_MIN_SCALE) * (1 - deceleratedProgress);
+ float scaleProgress = ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE
+ + (1 - ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE)
+ * (1 - deceleratedProgress);
mAllAppScale.updateValue(scaleProgress);
}
@@ -311,6 +322,11 @@
/**
* Creates an animation which updates the vertical transition progress and updates all the
* dependent UI using various animation events
+ *
+ * This method also dictates where along the progress the haptics should be played. As the user
+ * scrolls up from workspace or down from AllApps, a drag haptic is being played until the
+ * commit point where it plays a commit haptic. Where we play the haptics differs when going
+ * from workspace -> allApps and vice versa.
*/
@Override
public void setStateWithAnimation(LauncherState toState,
@@ -339,6 +355,20 @@
});
}
+ if(FeatureFlags.ENABLE_HAPTICS_ALL_APPS.get() && config.userControlled
+ && Utilities.ATLEAST_S) {
+ if (toState == ALL_APPS) {
+ builder.addOnFrameListener(
+ new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
+ SWIPE_DRAG_COMMIT_THRESHOLD, 1));
+ } else {
+ builder.addOnFrameListener(
+ new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
+ 0, SWIPE_DRAG_COMMIT_THRESHOLD));
+ }
+ builder.addEndListener(mVibratorWrapper::cancelVibrate);
+ }
+
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -356,7 +386,7 @@
setAlphas(toState, config, builder);
- if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL)) {
+ if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL) && !(Utilities.ATLEAST_S)) {
mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
}
@@ -376,6 +406,8 @@
Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
setter.setFloat(getAppsViewProgressAlpha(), MultiPropertyFactory.MULTI_PROPERTY_VALUE,
hasAllAppsContent ? 1 : 0, allAppsFade);
+ setter.setFloat(getAppsViewPullbackAlpha(), MultiPropertyFactory.MULTI_PROPERTY_VALUE,
+ hasAllAppsContent ? 1 : 0, allAppsFade);
boolean shouldProtectHeader =
ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS;
@@ -494,4 +526,45 @@
}
}
}
+
+ /**
+ * This VibrationAnimatorUpdateListener class takes in four parameters, a controller, start
+ * threshold, end threshold, and a Vibrator wrapper. We use the progress given by the controller
+ * as it gives an accurate progress that dictates where the vibrator should vibrate.
+ * Note: once the user begins a gesture and does the commit haptic, there should not be anymore
+ * haptics played for that gesture.
+ */
+ private static class VibrationAnimatorUpdateListener implements
+ ValueAnimator.AnimatorUpdateListener {
+ private final VibratorWrapper mVibratorWrapper;
+ private final AllAppsTransitionController mController;
+ private final float mStartThreshold;
+ private final float mEndThreshold;
+ private boolean mHasCommitted;
+
+ VibrationAnimatorUpdateListener(AllAppsTransitionController controller,
+ VibratorWrapper vibratorWrapper, float startThreshold,
+ float endThreshold) {
+ mController = controller;
+ mVibratorWrapper = vibratorWrapper;
+ mStartThreshold = startThreshold;
+ mEndThreshold = endThreshold;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (mHasCommitted) {
+ return;
+ }
+ float currentProgress =
+ AllAppsTransitionController.ALL_APPS_PROGRESS.get(mController);
+ if (currentProgress > mStartThreshold && currentProgress < mEndThreshold) {
+ mVibratorWrapper.vibrateForDragTexture();
+ } else if (!(currentProgress == 0 || currentProgress == 1)) {
+ // This check guards against committing at the location of the start of the gesture
+ mVibratorWrapper.vibrateForDragCommit();
+ mHasCommitted = true;
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index ff0a867..c98b60f 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -16,16 +16,13 @@
package com.android.launcher3.config;
+import static com.android.launcher3.uioverrides.flags.FlagsFactory.getDebugFlag;
+import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag;
+
import android.content.Context;
-import android.content.SharedPreferences;
import com.android.launcher3.BuildConfig;
import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.DeviceFlag;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
/**
* Defines a set of flags used to control various launcher behaviors.
@@ -34,26 +31,27 @@
*/
public final class FeatureFlags {
- private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
-
public static final String FLAGS_PREF_NAME = "featureFlags";
- private FeatureFlags() {
- }
+ private FeatureFlags() { }
public static boolean showFlagTogglerUi(Context context) {
- return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
+ return BuildConfig.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
}
/**
* True when the build has come from Android Studio and is being used for local debugging.
+ * @deprecated Use {@link BuildConfig#IS_STUDIO_BUILD} directly
*/
- public static final boolean IS_STUDIO_BUILD = BuildConfig.DEBUG;
+ @Deprecated
+ public static final boolean IS_STUDIO_BUILD = BuildConfig.IS_STUDIO_BUILD;
/**
* Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature
* and should be modified at a project level.
+ * @deprecated Use {@link BuildConfig#QSB_ON_FIRST_SCREEN} directly
*/
+ @Deprecated
public static final boolean QSB_ON_FIRST_SCREEN = BuildConfig.QSB_ON_FIRST_SCREEN;
/**
@@ -65,96 +63,88 @@
* Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"),
* and set a default value for the flag. This will be the default value on Debug builds.
*/
- public static final BooleanFlag ENABLE_INPUT_CONSUMER_REASON_LOGGING = getDebugFlag(
+ public static final BooleanFlag ENABLE_INPUT_CONSUMER_REASON_LOGGING = getDebugFlag(270390028,
"ENABLE_INPUT_CONSUMER_REASON_LOGGING",
true,
"Log the reason why an Input Consumer was selected for a gesture.");
- public static final BooleanFlag ENABLE_GESTURE_ERROR_DETECTION = getDebugFlag(
+ public static final BooleanFlag ENABLE_GESTURE_ERROR_DETECTION = getDebugFlag(270389990,
"ENABLE_GESTURE_ERROR_DETECTION",
true,
"Analyze gesture events and log detected errors");
// When enabled the promise icon is visible in all apps while installation an app.
- public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(
+ public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012,
"PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps");
- public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(
+ public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(270390904,
"KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper");
- public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
+ public static final BooleanFlag ENABLE_DEVICE_SEARCH = getReleaseFlag(270390907,
"ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
- getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
+ getDebugFlag(270390286, "ENABLE_FLOATING_SEARCH_BAR", false,
"Keep All Apps search bar at the bottom (but above keyboard if open)");
- public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
- true, "Hide header on keyboard before typing in all apps");
+ public static final BooleanFlag ENABLE_HIDE_HEADER = getReleaseFlag(270390930,
+ "ENABLE_HIDE_HEADER", true, "Hide header on keyboard before typing in all apps");
- public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = new DeviceFlag(
+ public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = getReleaseFlag(270390779,
"ENABLE_EXPANDING_PAUSE_WORK_BUTTON", false,
"Expand and collapse pause work button while scrolling");
- public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
+ public static final BooleanFlag ENABLE_RECENT_BLOCK = getDebugFlag(270390950,
+ "ENABLE_RECENT_BLOCK", false, "Show recently tapped search target block in zero state");
+
+ public static final BooleanFlag COLLECT_SEARCH_HISTORY = getReleaseFlag(270391455,
"COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
- public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(
+ public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
"ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps.");
- public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = new DeviceFlag(
- "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", false,
+ public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = getReleaseFlag(
+ 270391397, "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", false,
"Allows on device search in all apps logging");
- public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(
+ public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
"IME_STICKY_SNACKBAR_EDU", true, "Show sticky IME edu in AllApps");
- public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(
+ public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(270391653,
"ENABLE_PEOPLE_TILE_PREVIEW", false,
"Experimental: Shows conversation shortcuts on home screen as search results");
- public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(
+ public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638,
"FOLDER_NAME_MAJORITY_RANKING", true,
"Suggests folder names based on majority based ranking.");
- public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = new DeviceFlag(
- "INJECT_FALLBACK_APP_CORPUS_RESULTS", false, "Inject "
- + "fallback app corpus result when AiAi fails to return it.");
+ public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = getReleaseFlag(270391706,
+ "INJECT_FALLBACK_APP_CORPUS_RESULTS", false,
+ "Inject fallback app corpus result when AiAi fails to return it.");
- public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag(
+ public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag(270391641,
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
- public static final BooleanFlag ENABLE_BULK_WORKSPACE_ICON_LOADING = getDebugFlag(
+ public static final BooleanFlag ENABLE_BULK_WORKSPACE_ICON_LOADING = getDebugFlag(270392203,
"ENABLE_BULK_WORKSPACE_ICON_LOADING",
true,
"Enable loading workspace icons in bulk.");
- public static final BooleanFlag ENABLE_BULK_ALL_APPS_ICON_LOADING = getDebugFlag(
+ public static final BooleanFlag ENABLE_BULK_ALL_APPS_ICON_LOADING = getDebugFlag(270392465,
"ENABLE_BULK_ALL_APPS_ICON_LOADING",
true,
"Enable loading all apps icons in bulk.");
- // Keep as DeviceFlag for remote disable in emergency.
- public static final BooleanFlag ENABLE_OVERVIEW_SELECTIONS = new DeviceFlag(
- "ENABLE_OVERVIEW_SELECTIONS", true, "Show Select Mode button in Overview Actions");
-
- public static final BooleanFlag ENABLE_WIDGETS_PICKER_AIAI_SEARCH = new DeviceFlag(
- "ENABLE_WIDGETS_PICKER_AIAI_SEARCH", true, "Enable AiAi search in the widgets picker");
-
- public static final BooleanFlag ENABLE_OVERVIEW_SHARING_TO_PEOPLE = getDebugFlag(
- "ENABLE_OVERVIEW_SHARING_TO_PEOPLE", true,
- "Show indicators for content on Overview to share with top people. ");
-
- public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(
+ public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(270392706,
"ENABLE_DATABASE_RESTORE", false,
"Enable database restore when new restore session is created");
- public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(
+ public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(270391664,
"ENABLE_SMARTSPACE_DISMISS", true,
"Adds a menu option to dismiss the current Enhanced Smartspace card.");
- public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag(
+ public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag(270392629,
"ENABLE_OVERLAY_CONNECTION_OPTIM",
false,
"Enable optimizing overlay service connection");
@@ -162,340 +152,256 @@
/**
* Enables region sampling for text color: Needs system health assessment before turning on
*/
- public static final BooleanFlag ENABLE_REGION_SAMPLING = getDebugFlag(
+ public static final BooleanFlag ENABLE_REGION_SAMPLING = getDebugFlag(270391669,
"ENABLE_REGION_SAMPLING", false,
"Enable region sampling to determine color of text on screen.");
public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
- getDebugFlag(
+ getDebugFlag(270393096,
"ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false,
"Always use hardware optimization for folder animations.");
- public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag(
+ public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag(270392980,
"SEPARATE_RECENTS_ACTIVITY", false,
"Uses a separate recents activity instead of using the integrated recents+Launcher UI");
- public static final BooleanFlag ENABLE_MINIMAL_DEVICE = getDebugFlag(
+ public static final BooleanFlag ENABLE_MINIMAL_DEVICE = getDebugFlag(270392984,
"ENABLE_MINIMAL_DEVICE", false,
"Allow user to toggle minimal device mode in launcher.");
- // TODO: b/172467144 Remove ENABLE_LAUNCHER_ACTIVITY_THEME_CROSSFADE feature flag.
- public static final BooleanFlag ENABLE_LAUNCHER_ACTIVITY_THEME_CROSSFADE = new DeviceFlag(
- "ENABLE_LAUNCHER_ACTIVITY_THEME_CROSSFADE", false, "Enables a "
- + "crossfade animation when the system these changes.");
-
- // TODO: b/174174514 Remove ENABLE_APP_PREDICTIONS_WHILE_VISIBLE feature flag.
- public static final BooleanFlag ENABLE_APP_PREDICTIONS_WHILE_VISIBLE = new DeviceFlag(
- "ENABLE_APP_PREDICTIONS_WHILE_VISIBLE", true, "Allows app "
- + "predictions to be updated while they are visible to the user.");
-
public static final BooleanFlag ENABLE_TASKBAR_POPUP_MENU = getDebugFlag(
- "ENABLE_TASKBAR_POPUP_MENU", true, "Enables long pressing taskbar icons to show the"
- + " popup menu.");
+ 270392477, "ENABLE_TASKBAR_POPUP_MENU", true,
+ "Enables long pressing taskbar icons to show the popup menu.");
- public static final BooleanFlag ENABLE_TWO_PANEL_HOME = getDebugFlag(
+ public static final BooleanFlag ENABLE_TWO_PANEL_HOME = getDebugFlag(270392643,
"ENABLE_TWO_PANEL_HOME", true,
"Uses two panel on home screen. Only applicable on large screen devices.");
- public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(
+ public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(270393276,
"ENABLE_SCRIM_FOR_APP_LAUNCH", false,
"Enables scrim during app launch animation.");
- public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag(
+ public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = getReleaseFlag(270393258,
"ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets");
- public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false,
+ public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(
+ 270393108, "NOTIFY_CRASHES", false,
"Sends a notification whenever launcher encounters an uncaught exception.");
- public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(
+ public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(270393604,
"ENABLE_WALLPAPER_SCRIM", false,
"Enables scrim over wallpaper for text protection.");
- public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(
+ public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(270393268,
"WIDGETS_IN_LAUNCHER_PREVIEW", true,
"Enables widgets in Launcher preview for the Wallpaper app.");
- public static final BooleanFlag QUICK_WALLPAPER_PICKER = getDebugFlag(
+ public static final BooleanFlag QUICK_WALLPAPER_PICKER = getDebugFlag(270393112,
"QUICK_WALLPAPER_PICKER", true,
"Shows quick wallpaper picker in long-press menu");
- public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(
+ public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(270393426,
"ENABLE_BACK_SWIPE_HOME_ANIMATION", true,
"Enables home animation to icon when user swipes back.");
- public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag(
+ public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag(270393294,
"ENABLE_ICON_LABEL_AUTO_SCALING", true,
"Enables scaling/spacing for icon labels to make more characters visible");
- public static final BooleanFlag ENABLE_ALL_APPS_IN_TASKBAR = getDebugFlag(
- "ENABLE_ALL_APPS_IN_TASKBAR", true,
- "Enables accessing All Apps from the system Taskbar.");
-
- public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(
+ public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897,
"ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", false,
"Enables displaying the all apps button in the hotseat.");
- public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag(
+ public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
"ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false,
"Enables One Search box in Taskbar All Apps.");
- public static final BooleanFlag ENABLE_TASKBAR_IN_OVERVIEW = getDebugFlag(
- "ENABLE_TASKBAR_IN_OVERVIEW", true,
- "Enables accessing the system Taskbar in overview.");
-
- public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(
+ public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(270393906,
"ENABLE_SPLIT_FROM_WORKSPACE", true,
"Enable initiating split screen from workspace.");
public static final BooleanFlag ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS =
- getDebugFlag("ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", false,
+ getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", false,
"Enable splitting from fullscreen app with keyboard shortcuts");
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
- "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", false,
+ 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", false,
"Enable initiating split screen from workspace to workspace.");
- public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(
+ public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(270393455,
"ENABLE_NEW_MIGRATION_LOGIC", true,
"Enable the new grid migration logic, keeping pages when src < dest");
- public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(
+ public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(270394384,
"ENABLE_WIDGET_HOST_IN_BACKGROUND", false,
"Enable background widget updates listening for widget holder");
- public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag(
+ public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = getReleaseFlag(270394223,
"ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch.");
- public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = new DeviceFlag(
- "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false,
+ public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = getReleaseFlag(
+ 270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false,
"Enable option to replace decorator-based search result backgrounds with drawables");
- public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = new DeviceFlag(
- "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", false,
+ public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = getReleaseFlag(
+ 270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", false,
"Enable option to launch search results using the new view container transitions");
- public static final BooleanFlag TWO_PREDICTED_ROWS_ALL_APPS_SEARCH = new DeviceFlag(
- "TWO_PREDICTED_ROWS_ALL_APPS_SEARCH", false,
- "Use 2 rows of app predictions in All Apps search zero-state");
-
- public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = new DeviceFlag(
- "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true,
+ public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
+ 270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true,
"Enable option to show keyboard when going to all-apps");
- public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(
+ public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973,
"USE_LOCAL_ICON_OVERRIDES", true,
"Use inbuilt monochrome icons if app doesn't provide one");
- public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(
+ public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
"ENABLE_DISMISS_PREDICTION_UNDO", false,
"Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
- public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag(
+ public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag(270395008,
"ENABLE_CACHED_WIDGET", true,
"Show previously cached widgets as opposed to deferred widget where available");
- public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(
+ public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010,
"USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", false,
"Use local overrides for search request timeout");
- public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(
+ public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
"CONTINUOUS_VIEW_TREE_CAPTURE", false, "Capture View tree every frame");
- public static final BooleanFlag FOLDABLE_WORKSPACE_REORDER = getDebugFlag(
+ public static final BooleanFlag FOLDABLE_WORKSPACE_REORDER = getDebugFlag(270395070,
"FOLDABLE_WORKSPACE_REORDER", true,
"In foldables, when reordering the icons and widgets, is now going to use both sides");
- public static final BooleanFlag ENABLE_WIDGET_PICKER_DEPTH = new DeviceFlag(
- "ENABLE_WIDGET_PICKER_DEPTH", true, "Enable changing depth in widget picker.");
-
- public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag(
+ public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag(270395073,
"ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", false,
"Allow bottom sheet depth to be smaller than 1 for multi-display devices.");
- public static final BooleanFlag SCROLL_TOP_TO_RESET = new DeviceFlag(
- "SCROLL_TOP_TO_RESET", true, "Bring up IME and focus on "
- + "input when scroll to top if 'Always show keyboard' is enabled or in prefix state");
+ public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag(
+ 270395177, "SCROLL_TOP_TO_RESET", true,
+ "Bring up IME and focus on input when scroll to top if 'Always show keyboard'"
+ + " is enabled or in prefix state");
- public static final BooleanFlag POPUP_MATERIAL_U = new DeviceFlag(
- "POPUP_MATERIAL_U", false, "Switch popup UX to use material U");
+ public static final BooleanFlag ENABLE_MATERIAL_U_POPUP = getDebugFlag(270395516,
+ "ENABLE_MATERIAL_U_POPUP", false, "Switch popup UX to use material U");
- public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = new DeviceFlag(
+ public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = getReleaseFlag(270395269,
"ENABLE_SEARCH_UNINSTALLED_APPS", false, "Search uninstalled app results.");
- public static final BooleanFlag SHOW_HOME_GARDENING = getDebugFlag(
+ public static final BooleanFlag SHOW_HOME_GARDENING = getDebugFlag(270395183,
"SHOW_HOME_GARDENING", false,
"Show the new home gardening mode");
- public static final BooleanFlag HOME_GARDENING_WORKSPACE_BUTTONS = getDebugFlag(
+ public static final BooleanFlag HOME_GARDENING_WORKSPACE_BUTTONS = getDebugFlag(270395133,
"HOME_GARDENING_WORKSPACE_BUTTONS", false,
"Change workspace edit buttons to reflect home gardening");
- public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V2 = new DeviceFlag(
+ public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V2 = getReleaseFlag(270395134,
"ENABLE_DOWNLOAD_APP_UX_V2", true, "Updates the download app UX"
+ " to have better visuals");
- public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V3 = getDebugFlag(
+ public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V3 = getDebugFlag(270395186,
"ENABLE_DOWNLOAD_APP_UX_V3", false, "Updates the download app UX"
- + " to have better visuals, improve contrast, and color");
+ + " to have better visuals, improve contrast, and color");
- public static final BooleanFlag FORCE_PERSISTENT_TASKBAR = getDebugFlag(
+ public static final BooleanFlag FORCE_PERSISTENT_TASKBAR = getDebugFlag(270395077,
"FORCE_PERSISTENT_TASKBAR", false, "Forces taskbar to be persistent, even in gesture"
+ " nav mode and when transient taskbar is enabled.");
- public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(
+ public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
"FOLDABLE_SINGLE_PAGE", false,
"Use a single page for the workspace");
- public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(
+ public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
"ENABLE_TRANSIENT_TASKBAR", true, "Enables transient taskbar.");
- public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(
+ public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(270395140,
"SECONDARY_DRAG_N_DROP_TO_PIN", false,
"Enable dragging and dropping to pin apps within secondary display");
- public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(
+ public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143,
+ "ENABLE_ICON_IN_TEXT_HEADER", false, "Show icon in textheader");
+
+ public static final BooleanFlag ENABLE_APP_ICON_FOR_INLINE_SHORTCUTS = getDebugFlag(270395087,
+ "ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", false, "Show app icon for inline shortcut");
+
+ public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(270395278,
"SHOW_DOT_PAGINATION", false, "Enable showing dot pagination in workspace");
- public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag(
+ public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag(270395809,
"LARGE_SCREEN_WIDGET_PICKER", false, "Enable new widget picker that takes "
+ "advantage of large screen format");
- public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(
+ public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
"ENABLE_NEW_GESTURE_NAV_TUTORIAL", false,
"Enable the redesigned gesture navigation tutorial");
- public static final BooleanFlag ENABLE_DEVICE_PROFILE_LOGGING = new DeviceFlag(
- "ENABLE_DEVICE_PROFILE_LOGGING", false, "Allows DeviceProfile logging");
-
- public static final BooleanFlag ENABLE_LAUNCH_FROM_STAGED_APP = getDebugFlag(
+ public static final BooleanFlag ENABLE_LAUNCH_FROM_STAGED_APP = getDebugFlag(270395567,
"ENABLE_LAUNCH_FROM_STAGED_APP", true,
"Enable the ability to tap a staged app during split select to launch it in full screen"
);
- public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(
+ public static final BooleanFlag ENABLE_HAPTICS_ALL_APPS = getDebugFlag(270396358,
+ "ENABLE_HAPTICS_ALL_APPS", false, "Enables haptics opening/closing All apps");
+
+ public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(270396209,
"ENABLE_FORCED_MONO_ICON", false,
"Enable the ability to generate monochromatic icons, if it is not provided by the app"
);
- public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag(
+ public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag(270396268,
"ENABLE_TASKBAR_EDU_TOOLTIP", true,
"Enable the tooltip version of the Taskbar education flow.");
- public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(
+ public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
"ENABLE_MULTI_INSTANCE", false,
"Enables creation and filtering of multiple task instances in overview");
- public static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(
+ public static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(270396583,
"ENABLE_TASKBAR_PINNING", false,
"Enables taskbar pinning to allow user to switch between transient and persistent "
+ "taskbar flavors");
- public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(
+ public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206,
"ENABLE_GRID_ONLY_OVERVIEW", false,
"Enable a grid-only overview without a focused task.");
- public static void initialize(Context context) {
- synchronized (sDebugFlags) {
- for (DebugFlag flag : sDebugFlags) {
- flag.initialize(context);
- }
+ public static final BooleanFlag RECEIVE_UNFOLD_EVENTS_FROM_SYSUI = getDebugFlag(270397209,
+ "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", true,
+ "Enables receiving unfold animation events from sysui instead of calculating "
+ + "them in launcher process using hinge sensor values.");
- sDebugFlags.sort((f1, f2) -> {
- // Sort first by any prefs that the user has changed, then alphabetically.
- int changeComparison = Boolean.compare(f2.mHasBeenChangedAtLeastOnce,
- f1.mHasBeenChangedAtLeastOnce);
- return changeComparison != 0
- ? changeComparison
- : f1.key.compareToIgnoreCase(f2.key);
- });
- }
- }
-
- static List<DebugFlag> getDebugFlags() {
- synchronized (sDebugFlags) {
- return new ArrayList<>(sDebugFlags);
- }
- }
-
- public static void dump(PrintWriter pw) {
- pw.println("DeviceFlags:");
- synchronized (sDebugFlags) {
- for (DebugFlag flag : sDebugFlags) {
- if (flag instanceof DeviceFlag) {
- pw.println(" " + flag.toString());
- }
- }
- }
- pw.println("DebugFlags:");
- synchronized (sDebugFlags) {
- for (DebugFlag flag : sDebugFlags) {
- if (!(flag instanceof DeviceFlag)) {
- pw.println(" " + flag.toString());
- }
- }
- }
- }
+ public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844,
+ "ENABLE_KEYBOARD_QUICK_SWITCH", false,
+ "Enables keyboard quick switching");
public static class BooleanFlag {
- public final String key;
- public final boolean defaultValue;
+ private final boolean mCurrentValue;
- public BooleanFlag(String key, boolean defaultValue) {
- this.key = key;
- this.defaultValue = defaultValue;
+ public BooleanFlag(boolean currentValue) {
+ mCurrentValue = currentValue;
}
public boolean get() {
- return defaultValue;
- }
-
- @Override
- public String toString() {
- return appendProps(new StringBuilder()).toString();
- }
-
- protected StringBuilder appendProps(StringBuilder src) {
- return src.append(key).append(", defaultValue=").append(defaultValue);
- }
- }
-
- public static class DebugFlag extends BooleanFlag {
-
- public final String description;
- protected boolean mHasBeenChangedAtLeastOnce;
- protected boolean mCurrentValue;
-
- public DebugFlag(String key, boolean defaultValue, String description) {
- super(key, defaultValue);
- this.description = description;
- mCurrentValue = this.defaultValue;
- synchronized (sDebugFlags) {
- sDebugFlags.add(this);
- }
- }
-
- @Override
- public boolean get() {
return mCurrentValue;
}
-
- public void initialize(Context context) {
- SharedPreferences prefs =
- context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
- mHasBeenChangedAtLeastOnce = prefs.contains(key);
- mCurrentValue = prefs.getBoolean(key, defaultValue);
- }
-
- @Override
- protected StringBuilder appendProps(StringBuilder src) {
- return super.appendProps(src).append(", mCurrentValue=").append(mCurrentValue);
- }
}
- private static BooleanFlag getDebugFlag(String key, boolean defaultValue, String description) {
- return Utilities.IS_DEBUG_DEVICE
- ? new DebugFlag(key, defaultValue, description)
- : new BooleanFlag(key, defaultValue);
+ /**
+ * Class representing an integer flag
+ */
+ public static class IntFlag {
+
+ private final int mCurrentValue;
+
+ public IntFlag(int currentValue) {
+ mCurrentValue = currentValue;
+ }
+
+ public int get() {
+ return mCurrentValue;
+ }
}
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index f54d05d..46c8e81 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -56,7 +56,6 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
@@ -84,6 +83,7 @@
protected final int mRegistrationX;
protected final int mRegistrationY;
private final float mInitialScale;
+ private final float mEndScale;
protected final float mScaleOnDrop;
protected final int[] mTempLoc = new int[2];
@@ -159,7 +159,7 @@
setClipToPadding(false);
}
- final float scale = (width + finalScaleDps) / width;
+ mEndScale = (width + finalScaleDps) / width;
// Set the initial scale to avoid any jumps
setScaleX(initialScale);
@@ -170,8 +170,8 @@
mAnim.setDuration(VIEW_ZOOM_DURATION);
mAnim.addUpdateListener(animation -> {
final float value = (Float) animation.getAnimatedValue();
- setScaleX(initialScale + (value * (scale - initialScale)));
- setScaleY(initialScale + (value * (scale - initialScale)));
+ setScaleX(Utilities.mapRange(value, initialScale, mEndScale));
+ setScaleY(Utilities.mapRange(value, initialScale, mEndScale));
if (!isAttachedToWindow()) {
animation.cancel();
}
@@ -218,12 +218,6 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public void setItemInfo(final ItemInfo info) {
- if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- && info.itemType != LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION
- && info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
- && info.itemType != LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
- return;
- }
// Load the adaptive icon on a background thread and add the view in ui thread.
MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
Object[] outObj = new Object[1];
@@ -515,6 +509,10 @@
return mInitialScale;
}
+ public float getEndScale() {
+ return mEndScale;
+ }
+
@Override
public boolean hasOverlappingRendering() {
return false;
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index f9916d0..6b21522 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -44,7 +44,7 @@
* request.
*/
@TargetApi(Build.VERSION_CODES.O)
-class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo {
+public class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo {
// Class name used in the target component, such that it will never represent an
// actual existing class.
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 9a5d77e..c9fe745 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1263,7 +1263,7 @@
PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
? (PendingAddShortcutInfo) d.dragInfo : null;
WorkspaceItemInfo pasiSi =
- pasi != null ? pasi.activityInfo.createWorkspaceItemInfo() : null;
+ pasi != null ? pasi.getActivityInfo(launcher).createWorkspaceItemInfo() : null;
if (pasi != null && pasiSi == null) {
// There is no WorkspaceItemInfo, so we have to go through a configuration activity.
pasi.container = mInfo.id;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index e69f781..ee1a060 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -135,6 +135,9 @@
private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0);
private float mTranslationXForTaskbarAlignmentAnimation = 0f;
+ private float mTranslationYForTaskbarAlignmentAnimation = 0f;
+ private float mTranslationXForTaskbarRevealAnimation = 0f;
+ private float mTranslationYForTaskbarRevealAnimation = 0f;
private final PointF mTranslationForReorderBounce = new PointF(0, 0);
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
@@ -416,7 +419,7 @@
() -> {
mPreviewItemManager.hidePreviewItem(finalIndex, false);
mFolder.showItem(item);
- },
+ },
DragLayer.ANIMATION_END_DISAPPEAR, null);
mFolder.hideItem(item);
@@ -768,11 +771,15 @@
}
private void updateTranslation() {
- super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x
+ super.setTranslationX(mTranslationForReorderBounce.x
+ + mTranslationForReorderPreview.x
+ mTranslationForMoveFromCenterAnimation.x
- + mTranslationXForTaskbarAlignmentAnimation);
+ + mTranslationXForTaskbarAlignmentAnimation
+ + mTranslationXForTaskbarRevealAnimation);
super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y
- + mTranslationForMoveFromCenterAnimation.y);
+ + mTranslationForMoveFromCenterAnimation.y
+ + mTranslationYForTaskbarAlignmentAnimation
+ + mTranslationYForTaskbarRevealAnimation);
}
public void setReorderBounceOffset(float x, float y) {
@@ -787,7 +794,7 @@
/**
* Sets translationX value for taskbar to launcher alignment animation
*/
- public void setTranslationForTaskbarAlignmentAnimation(float translationX) {
+ public void setTranslationXForTaskbarAlignmentAnimation(float translationX) {
mTranslationXForTaskbarAlignmentAnimation = translationX;
updateTranslation();
}
@@ -800,6 +807,51 @@
}
/**
+ * Sets translationY value for taskbar to launcher alignment animation
+ */
+ public void setTranslationYForTaskbarAlignmentAnimation(float translationY) {
+ mTranslationYForTaskbarAlignmentAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translation values for taskbar to launcher alignment animation
+ */
+ public float getTranslationYForTaskbarAlignmentAnimation() {
+ return mTranslationYForTaskbarAlignmentAnimation;
+ }
+
+ /**
+ * Sets translationX value for taskbar reveal animation
+ */
+ public void setTranslationXForTaskbarRevealAnimation(float translationX) {
+ mTranslationXForTaskbarRevealAnimation = translationX;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translation values for taskbar reveal animation
+ */
+ public float getTranslationXForTaskbarRevealAnimation() {
+ return mTranslationXForTaskbarRevealAnimation;
+ }
+
+ /**
+ * Sets translationY value for taskbar reveal animation
+ */
+ public void setTranslationYForTaskbarRevealAnimation(float translationY) {
+ mTranslationYForTaskbarRevealAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translationY values for taskbar reveal animation
+ */
+ public float getTranslationYForTaskbarRevealAnimation() {
+ return mTranslationYForTaskbarRevealAnimation;
+ }
+
+ /**
* Sets translation values for move from center animation
*/
public void setTranslationForMoveFromCenterAnimation(float x, float y) {
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 9426c22..2c8f1f3 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -138,12 +138,14 @@
}
idp.setCurrentGrid(getContext(), gridName);
+ getContext().getContentResolver().notifyChange(uri, null);
return 1;
}
case ICON_THEMED:
case SET_ICON_THEMED: {
LauncherPrefs.get(getContext())
.put(THEMED_ICONS, values.getAsBoolean(BOOLEAN_VALUE));
+ getContext().getContentResolver().notifyChange(uri, null);
return 1;
}
default:
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index f2fde0e..5a50569 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -92,7 +92,7 @@
private static final int PRELOAD_BACKGROUND_COLOR_INDEX = 1;
private static final int ALPHA_DURATION_MILLIS = 3000;
- private static final int OVERLAY_ALPHA_RANGE = 127;
+ private static final int OVERLAY_ALPHA_RANGE = 191;
private static final long WAVE_MOTION_DELAY_FACTOR_MILLIS = 100;
private static final WeakHashMap<Integer, PorterDuffColorFilter> COLOR_FILTER_MAP =
new WeakHashMap<>();
@@ -138,7 +138,8 @@
IconPalette.getPreloadProgressColor(context, info.bitmap.color),
getPreloadColors(context),
Utilities.isDarkTheme(context),
- getRefreshRateMillis(context));
+ getRefreshRateMillis(context),
+ GraphicsUtils.getShapePath(context, DEFAULT_PATH_SIZE));
}
public PreloadIconDrawable(
@@ -146,10 +147,11 @@
int indicatorColor,
int[] preloadColors,
boolean isDarkMode,
- int refreshRateMillis) {
+ int refreshRateMillis,
+ Path shapePath) {
super(info.bitmap);
mItem = info;
- mShapePath = GraphicsUtils.getShapePath(DEFAULT_PATH_SIZE);
+ mShapePath = shapePath;
mScaledTrackPath = new Path();
mScaledProgressPath = new Path();
@@ -386,7 +388,8 @@
mIndicatorColor,
new int[] {mSystemAccentColor, mSystemBackgroundColor},
mIsDarkMode,
- mRefreshRateMillis);
+ mRefreshRateMillis,
+ mShapePath);
}
@Override
@@ -442,6 +445,7 @@
protected final boolean mIsDarkMode;
protected final int mLevel;
protected final int mRefreshRateMillis;
+ private final Path mShapePath;
public PreloadIconConstantState(
Bitmap bitmap,
@@ -450,7 +454,8 @@
int indicatorColor,
int[] preloadColors,
boolean isDarkMode,
- int refreshRateMillis) {
+ int refreshRateMillis,
+ Path shapePath) {
super(bitmap, iconColor);
mInfo = info;
mIndicatorColor = indicatorColor;
@@ -458,6 +463,7 @@
mIsDarkMode = isDarkMode;
mLevel = info.getProgressLevel();
mRefreshRateMillis = refreshRateMillis;
+ mShapePath = shapePath;
}
@Override
@@ -467,7 +473,8 @@
mIndicatorColor,
mPreloadColors,
mIsDarkMode,
- mRefreshRateMillis);
+ mRefreshRateMillis,
+ mShapePath);
}
}
}
diff --git a/src/com/android/launcher3/graphics/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java
index 11e7dc8..e983a30 100644
--- a/src/com/android/launcher3/graphics/SysUiScrim.java
+++ b/src/com/android/launcher3/graphics/SysUiScrim.java
@@ -32,11 +32,10 @@
import android.util.DisplayMetrics;
import android.util.FloatProperty;
import android.view.View;
-import android.view.WindowInsets;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.DynamicResource;
@@ -185,21 +184,18 @@
/**
* Determines whether to draw the top and/or bottom scrim based on new insets.
+ *
+ * In order for the bottom scrim to be drawn this 3 condition should be meet at the same time:
+ * the device is in 3 button navigation, the taskbar is not present and the Hotseat is
+ * horizontal
*/
public void onInsetsChanged(Rect insets) {
+ DeviceProfile dp = mActivity.getDeviceProfile();
mDrawTopScrim = mTopScrim != null && insets.top > 0;
mDrawBottomScrim = mBottomMask != null
- && !mActivity.getDeviceProfile().isVerticalBarLayout()
- && hasBottomNavButtons();
- }
-
- private boolean hasBottomNavButtons() {
- if (Utilities.ATLEAST_Q && mActivity.getRootView() != null
- && mActivity.getRootView().getRootWindowInsets() != null) {
- WindowInsets windowInsets = mActivity.getRootView().getRootWindowInsets();
- return windowInsets.getTappableElementInsets().bottom > 0;
- }
- return true;
+ && !dp.isVerticalBarLayout()
+ && !dp.isGestureMode
+ && !dp.isTaskbarPresent;
}
@Override
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 0b4a4a5..3c63f26 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -60,6 +60,7 @@
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.InstantAppResolver;
@@ -81,6 +82,11 @@
*/
public class IconCache extends BaseIconCache {
+ // Shortcut extra which can point to a packageName and can be used to indicate an alternate
+ // badge info. Launcher only reads this if the shortcut comes from a system app.
+ public static final String EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE =
+ "extra_shortcut_badge_override_package";
+
private static final String TAG = "Launcher.IconCache";
private final Predicate<ItemInfoWithIcon> mIsUsingFallbackOrNonDefaultIconCheck = w ->
@@ -260,8 +266,15 @@
getTitleAndIcon(appInfo, false);
return appInfo.bitmap;
} else {
- PackageItemInfo pkgInfo = new PackageItemInfo(shortcutInfo.getPackage(),
- shortcutInfo.getUserHandle());
+ String pkg = shortcutInfo.getPackage();
+ String override = shortcutInfo.getExtras() == null ? null
+ : shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE);
+ if (!TextUtils.isEmpty(override)
+ && InstallSessionHelper.INSTANCE.get(mContext)
+ .isTrustedPackage(pkg, shortcutInfo.getUserHandle())) {
+ pkg = override;
+ }
+ PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle());
getTitleAndIconForApp(pkgInfo, false);
return pkgInfo.bitmap;
}
@@ -484,8 +497,7 @@
WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext)
.get(infoInOut.widgetCategory);
infoInOut.title = mContext.getString(widgetSection.mSectionTitle);
- infoInOut.contentDescription = mPackageManager.getUserBadgedLabel(
- infoInOut.title, infoInOut.user);
+ infoInOut.contentDescription = getUserBadgedLabel(infoInOut.title, infoInOut.user);
final BitmapInfo cachedBitmap = mWidgetCategoryBitmapInfos.get(infoInOut.widgetCategory);
if (cachedBitmap != null) {
infoInOut.bitmap = getBadgedIcon(cachedBitmap, infoInOut.user);
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 9f8db51..8519a3e 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -246,6 +246,9 @@
sortWorkspaceItemsSpatially(idp, otherWorkspaceItems);
// Tell the workspace that we're about to start binding items
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "scheduling: startBinding");
+ }
executeCallbacksTask(c -> {
c.clearPendingBinds();
c.startBinding();
@@ -264,6 +267,9 @@
Executor pendingExecutor = pendingTasks::add;
bindWorkspaceItems(otherWorkspaceItems, pendingExecutor);
bindAppWidgets(otherAppWidgets, pendingExecutor);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.FLAKY_BINDING, "scheduling: finishBindingItems");
+ }
executeCallbacksTask(c -> c.finishBindingItems(currentScreenIds), pendingExecutor);
pendingExecutor.execute(
() -> {
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 6c62b31..855a69d 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -37,7 +37,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
@@ -72,24 +71,32 @@
private final IconCache mIconCache;
private final InvariantDeviceProfile mIDP;
- private final IntArray itemsToRemove = new IntArray();
- private final IntArray restoredRows = new IntArray();
- private final IntSparseArrayMap<GridOccupancy> occupied = new IntSparseArrayMap<>();
+ private final IntArray mItemsToRemove = new IntArray();
+ private final IntArray mRestoredRows = new IntArray();
+ private final IntSparseArrayMap<GridOccupancy> mOccupied = new IntSparseArrayMap<>();
- private final int iconPackageIndex;
- private final int iconResourceIndex;
- private final int iconIndex;
- public final int titleIndex;
+ private final int mIconPackageIndex;
+ private final int mIconResourceIndex;
+ private final int mIconIndex;
+ public final int mTitleIndex;
- private final int idIndex;
- private final int containerIndex;
- private final int itemTypeIndex;
- private final int screenIndex;
- private final int cellXIndex;
- private final int cellYIndex;
- private final int profileIdIndex;
- private final int restoredIndex;
- private final int intentIndex;
+ private final int mIdIndex;
+ private final int mContainerIndex;
+ private final int mItemTypeIndex;
+ private final int mScreenIndex;
+ private final int mCellXIndex;
+ private final int mCellYIndex;
+ private final int mProfileIdIndex;
+ private final int mRestoredIndex;
+ private final int mIntentIndex;
+
+ private final int mAppWidgetIdIndex;
+ private final int mAppWidgetProviderIndex;
+ private final int mSpanXIndex;
+ private final int mSpanYIndex;
+ private final int mRankIndex;
+ private final int mOptionsIndex;
+ private final int mAppWidgetSourceIndex;
@Nullable
private LauncherActivityInfo mActivityInfo;
@@ -114,20 +121,28 @@
mPM = mContext.getPackageManager();
// Init column indices
- iconIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
- iconPackageIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
- iconResourceIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
- titleIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+ mIconIndex = getColumnIndexOrThrow(Favorites.ICON);
+ mIconPackageIndex = getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
+ mIconResourceIndex = getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
+ mTitleIndex = getColumnIndexOrThrow(Favorites.TITLE);
- idIndex = getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
- containerIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
- itemTypeIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
- screenIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
- cellXIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- cellYIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- profileIdIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
- restoredIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED);
- intentIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+ mIdIndex = getColumnIndexOrThrow(Favorites._ID);
+ mContainerIndex = getColumnIndexOrThrow(Favorites.CONTAINER);
+ mItemTypeIndex = getColumnIndexOrThrow(Favorites.ITEM_TYPE);
+ mScreenIndex = getColumnIndexOrThrow(Favorites.SCREEN);
+ mCellXIndex = getColumnIndexOrThrow(Favorites.CELLX);
+ mCellYIndex = getColumnIndexOrThrow(Favorites.CELLY);
+ mProfileIdIndex = getColumnIndexOrThrow(Favorites.PROFILE_ID);
+ mRestoredIndex = getColumnIndexOrThrow(Favorites.RESTORED);
+ mIntentIndex = getColumnIndexOrThrow(Favorites.INTENT);
+
+ mAppWidgetIdIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_ID);
+ mAppWidgetProviderIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
+ mSpanXIndex = getColumnIndexOrThrow(Favorites.SPANX);
+ mSpanYIndex = getColumnIndexOrThrow(Favorites.SPANY);
+ mRankIndex = getColumnIndexOrThrow(Favorites.RANK);
+ mOptionsIndex = getColumnIndexOrThrow(Favorites.OPTIONS);
+ mAppWidgetSourceIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_SOURCE);
}
@Override
@@ -137,18 +152,18 @@
mActivityInfo = null;
// Load common properties.
- itemType = getInt(itemTypeIndex);
- container = getInt(containerIndex);
- id = getInt(idIndex);
- serialNumber = getInt(profileIdIndex);
+ itemType = getInt(mItemTypeIndex);
+ container = getInt(mContainerIndex);
+ id = getInt(mIdIndex);
+ serialNumber = getInt(mProfileIdIndex);
user = allUsers.get(serialNumber);
- restoreFlag = getInt(restoredIndex);
+ restoreFlag = getInt(mRestoredIndex);
}
return result;
}
public Intent parseIntent() {
- String intentDescription = getString(intentIndex);
+ String intentDescription = getString(mIntentIndex);
try {
return TextUtils.isEmpty(intentDescription) ?
null : Intent.parseUri(intentDescription, 0);
@@ -185,14 +200,14 @@
public IconRequestInfo<WorkspaceItemInfo> createIconRequestInfo(
WorkspaceItemInfo wai, boolean useLowResIcon) {
- String packageName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
- ? getString(iconPackageIndex) : null;
- String resourceName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
- ? getString(iconResourceIndex) : null;
- byte[] iconBlob = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+ String packageName = itemType == Favorites.ITEM_TYPE_SHORTCUT
+ ? getString(mIconPackageIndex) : null;
+ String resourceName = itemType == Favorites.ITEM_TYPE_SHORTCUT
+ ? getString(mIconResourceIndex) : null;
+ byte[] iconBlob = itemType == Favorites.ITEM_TYPE_SHORTCUT
|| itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
|| restoreFlag != 0
- ? getBlob(iconIndex) : null;
+ ? getBlob(mIconIndex) : null;
return new IconRequestInfo<>(
wai, mActivityInfo, packageName, resourceName, iconBlob, useLowResIcon);
@@ -202,7 +217,70 @@
* Returns the title or empty string
*/
private String getTitle() {
- return Utilities.trim(getString(titleIndex));
+ return Utilities.trim(getString(mTitleIndex));
+ }
+
+ /**
+ * When loading an app widget for the workspace, returns it's app widget id
+ */
+ public int getAppWidgetId() {
+ return getInt(mAppWidgetIdIndex);
+ }
+
+ /**
+ * When loading an app widget for the workspace, returns the widget provider
+ */
+ public String getAppWidgetProvider() {
+ return getString(mAppWidgetProviderIndex);
+ }
+
+ /**
+ * Returns the x position for the item in the cell layout's grid
+ */
+ public int getSpanX() {
+ return getInt(mSpanXIndex);
+ }
+
+ /**
+ * Returns the y position for the item in the cell layout's grid
+ */
+ public int getSpanY() {
+ return getInt(mSpanYIndex);
+ }
+
+ /**
+ * Returns the rank for the item
+ */
+ public int getRank() {
+ return getInt(mRankIndex);
+ }
+
+ /**
+ * Returns the options for the item
+ */
+ public int getOptions() {
+ return getInt(mOptionsIndex);
+ }
+
+ /**
+ * When loading an app widget for the workspace, returns it's app widget source
+ */
+ public int getAppWidgetSource() {
+ return getInt(mAppWidgetSourceIndex);
+ }
+
+ /**
+ * Returns the screen that the item is on
+ */
+ public int getScreen() {
+ return getInt(mScreenIndex);
+ }
+
+ /**
+ * Returns the UX container that the item is in
+ */
+ public int getContainer() {
+ return getInt(mContainerIndex);
}
/**
@@ -232,7 +310,7 @@
throw new InvalidParameterException("Invalid restoreType " + restoreFlag);
}
- info.contentDescription = mPM.getUserBadgedLabel(info.title, info.user);
+ info.contentDescription = mIconCache.getUserBadgedLabel(info.title, info.user);
info.itemType = itemType;
info.status = restoreFlag;
return info;
@@ -303,7 +381,7 @@
}
}
- info.contentDescription = mPM.getUserBadgedLabel(info.title, info.user);
+ info.contentDescription = mIconCache.getUserBadgedLabel(info.title, info.user);
return info;
}
@@ -320,7 +398,7 @@
*/
public void markDeleted(String reason) {
FileLog.e(TAG, reason);
- itemsToRemove.add(id);
+ mItemsToRemove.add(id);
}
/**
@@ -328,10 +406,10 @@
* @return true is any item was removed.
*/
public boolean commitDeleted() {
- if (itemsToRemove.size() > 0) {
+ if (mItemsToRemove.size() > 0) {
// Remove dead items
mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery(
- LauncherSettings.Favorites._ID, itemsToRemove), null);
+ Favorites._ID, mItemsToRemove), null);
return true;
}
return false;
@@ -342,7 +420,7 @@
*/
public void markRestored() {
if (restoreFlag != 0) {
- restoredRows.add(id);
+ mRestoredRows.add(id);
restoreFlag = 0;
}
}
@@ -352,13 +430,13 @@
}
public void commitRestoredItems() {
- if (restoredRows.size() > 0) {
+ if (mRestoredRows.size() > 0) {
// Update restored items that no longer require special handling
ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.RESTORED, 0);
+ values.put(Favorites.RESTORED, 0);
mContext.getContentResolver().update(mContentUri, values,
Utilities.createDbSelectionQuery(
- LauncherSettings.Favorites._ID, restoredRows), null);
+ Favorites._ID, mRestoredRows), null);
}
}
@@ -366,8 +444,7 @@
* Returns true is the item is on workspace or hotseat
*/
public boolean isOnWorkspaceOrHotseat() {
- return container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
- container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+ return container == Favorites.CONTAINER_DESKTOP || container == Favorites.CONTAINER_HOTSEAT;
}
/**
@@ -381,9 +458,9 @@
public void applyCommonProperties(ItemInfo info) {
info.id = id;
info.container = container;
- info.screenId = getInt(screenIndex);
- info.cellX = getInt(cellXIndex);
- info.cellY = getInt(cellYIndex);
+ info.screenId = getInt(mScreenIndex);
+ info.cellX = getInt(mCellXIndex);
+ info.cellY = getInt(mCellYIndex);
}
public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
@@ -396,7 +473,7 @@
*/
public void checkAndAddItem(
ItemInfo info, BgDataModel dataModel, LoaderMemoryLogger logger) {
- if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
// Ensure that it is a valid intent. An exception here will
// cause the item loading to get skipped
ShortcutKey.fromItemInfo(info);
@@ -413,9 +490,9 @@
*/
protected boolean checkItemPlacement(ItemInfo item) {
int containerIndex = item.screenId;
- if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ if (item.container == Favorites.CONTAINER_HOTSEAT) {
final GridOccupancy hotseatOccupancy =
- occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
+ mOccupied.get(Favorites.CONTAINER_HOTSEAT);
if (item.screenId >= mIDP.numDatabaseHotseatIcons) {
Log.e(TAG, "Error loading shortcut " + item
@@ -438,19 +515,18 @@
} else {
final GridOccupancy occupancy = new GridOccupancy(mIDP.numDatabaseHotseatIcons, 1);
occupancy.cells[item.screenId][0] = true;
- occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
+ mOccupied.put(Favorites.CONTAINER_HOTSEAT, occupancy);
return true;
}
- } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ } else if (item.container != Favorites.CONTAINER_DESKTOP) {
// Skip further checking if it is not the hotseat or workspace container
return true;
}
final int countX = mIDP.numColumns;
final int countY = mIDP.numRows;
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- item.cellX < 0 || item.cellY < 0 ||
- item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
+ if (item.container == Favorites.CONTAINER_DESKTOP && item.cellX < 0 || item.cellY < 0
+ || item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
Log.e(TAG, "Error loading shortcut " + item
+ " into cell (" + containerIndex + "-" + item.screenId + ":"
+ item.cellX + "," + item.cellY
@@ -458,7 +534,7 @@
return false;
}
- if (!occupied.containsKey(item.screenId)) {
+ if (!mOccupied.containsKey(item.screenId)) {
GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
if (item.screenId == Workspace.FIRST_SCREEN_ID && FeatureFlags.QSB_ON_FIRST_SCREEN) {
// Mark the first X columns (X is width of the search container) in the first row as
@@ -468,9 +544,9 @@
int spanY = 1;
screen.markCells(0, 0, spanX, spanY, true);
}
- occupied.put(item.screenId, screen);
+ mOccupied.put(item.screenId, screen);
}
- final GridOccupancy occupancy = occupied.get(item.screenId);
+ final GridOccupancy occupancy = mOccupied.get(item.screenId);
// Check if any workspace icons overlap with each other
if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 46a6a66..da9be49 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -58,7 +58,8 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.LauncherSettings.Settings;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder;
@@ -198,7 +199,7 @@
}
Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
- TimingLogger logger = new TimingLogger(TAG, "run");
+ TimingLogger timingLogger = new TimingLogger(TAG, "run");
LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
@@ -208,7 +209,7 @@
} finally {
Trace.endSection();
}
- logASplit(logger, "loadWorkspace");
+ logASplit(timingLogger, "loadWorkspace");
// Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
// sanitizeData should not be invoked if the workspace is loaded from a db different
@@ -216,22 +217,23 @@
// (e.g. both grid preview and minimal device mode uses a different db)
if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
verifyNotStopped();
- sanitizeData();
- logASplit(logger, "sanitizeData");
+ sanitizeFolders(mItemsDeleted);
+ sanitizeWidgetsShortcutsAndPackages();
+ logASplit(timingLogger, "sanitizeData");
}
verifyNotStopped();
mLauncherBinder.bindWorkspace(true /* incrementBindId */);
- logASplit(logger, "bindWorkspace");
+ logASplit(timingLogger, "bindWorkspace");
mModelDelegate.workspaceLoadComplete();
// Notify the installer packages of packages with active installs on the first screen.
sendFirstScreenActiveInstallsBroadcast();
- logASplit(logger, "sendFirstScreenActiveInstallsBroadcast");
+ logASplit(timingLogger, "sendFirstScreenActiveInstallsBroadcast");
// Take a break
waitForIdle();
- logASplit(logger, "step 1 complete");
+ logASplit(timingLogger, "step 1 complete");
verifyNotStopped();
// second step
@@ -242,11 +244,11 @@
} finally {
Trace.endSection();
}
- logASplit(logger, "loadAllApps");
+ logASplit(timingLogger, "loadAllApps");
verifyNotStopped();
mLauncherBinder.bindAllApps();
- logASplit(logger, "bindAllApps");
+ logASplit(timingLogger, "bindAllApps");
verifyNotStopped();
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
@@ -254,69 +256,69 @@
updateHandler.updateIcons(allActivityList,
LauncherActivityCachingLogic.newInstance(mApp.getContext()),
mApp.getModel()::onPackageIconsUpdated);
- logASplit(logger, "update icon cache");
+ logASplit(timingLogger, "update icon cache");
verifyNotStopped();
- logASplit(logger, "save shortcuts in icon cache");
+ logASplit(timingLogger, "save shortcuts in icon cache");
updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),
mApp.getModel()::onPackageIconsUpdated);
// Take a break
waitForIdle();
- logASplit(logger, "step 2 complete");
+ logASplit(timingLogger, "step 2 complete");
verifyNotStopped();
// third step
List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
- logASplit(logger, "loadDeepShortcuts");
+ logASplit(timingLogger, "loadDeepShortcuts");
verifyNotStopped();
mLauncherBinder.bindDeepShortcuts();
- logASplit(logger, "bindDeepShortcuts");
+ logASplit(timingLogger, "bindDeepShortcuts");
verifyNotStopped();
- logASplit(logger, "save deep shortcuts in icon cache");
+ logASplit(timingLogger, "save deep shortcuts in icon cache");
updateHandler.updateIcons(allDeepShortcuts,
new ShortcutCachingLogic(), (pkgs, user) -> { });
// Take a break
waitForIdle();
- logASplit(logger, "step 3 complete");
+ logASplit(timingLogger, "step 3 complete");
verifyNotStopped();
// fourth step
List<ComponentWithLabelAndIcon> allWidgetsList =
mBgDataModel.widgetsModel.update(mApp, null);
- logASplit(logger, "load widgets");
+ logASplit(timingLogger, "load widgets");
verifyNotStopped();
mLauncherBinder.bindWidgets();
- logASplit(logger, "bindWidgets");
+ logASplit(timingLogger, "bindWidgets");
verifyNotStopped();
updateHandler.updateIcons(allWidgetsList,
new ComponentWithIconCachingLogic(mApp.getContext(), true),
mApp.getModel()::onWidgetLabelsUpdated);
- logASplit(logger, "save widgets in icon cache");
+ logASplit(timingLogger, "save widgets in icon cache");
// fifth step
loadFolderNames();
verifyNotStopped();
updateHandler.finish();
- logASplit(logger, "finish icon update");
+ logASplit(timingLogger, "finish icon update");
mModelDelegate.modelLoadComplete();
transaction.commit();
memoryLogger.clearLogs();
} catch (CancellationException e) {
// Loader stopped, ignore
- logASplit(logger, "Cancelled");
+ logASplit(timingLogger, "Cancelled");
} catch (Exception e) {
memoryLogger.printLogs();
throw e;
} finally {
- logger.dumpToLog();
+ timingLogger.dumpToLog();
}
TraceHelper.INSTANCE.endSection(traceToken);
}
@@ -326,9 +328,10 @@
this.notify();
}
- private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger logger) {
- loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI,
- null /* selection */, logger);
+ private void loadWorkspace(
+ List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger memoryLogger) {
+ loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI,
+ null /* selection */, memoryLogger);
}
protected void loadWorkspace(
@@ -340,7 +343,7 @@
List<ShortcutInfo> allDeepShortcuts,
Uri contentUri,
String selection,
- @Nullable LoaderMemoryLogger logger) {
+ @Nullable LoaderMemoryLogger memoryLogger) {
final Context context = mApp.getContext();
final ContentResolver contentResolver = context.getContentResolver();
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -356,13 +359,11 @@
if (clearDb) {
Log.d(TAG, "loadWorkspace: resetting launcher database");
- LauncherSettings.Settings.call(contentResolver,
- LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
+ Settings.call(contentResolver, Settings.METHOD_CREATE_EMPTY_DB);
}
Log.d(TAG, "loadWorkspace: loading default favorites");
- LauncherSettings.Settings.call(contentResolver,
- LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
+ Settings.call(contentResolver, Settings.METHOD_LOAD_DEFAULT_FAVORITES);
synchronized (mBgDataModel) {
mBgDataModel.clear();
@@ -380,24 +381,8 @@
contentResolver.query(contentUri, null, selection, null, null), contentUri,
mApp, mUserManagerState);
final Bundle extras = c.getExtras();
- mDbName = extras == null
- ? null : extras.getString(LauncherSettings.Settings.EXTRA_DB_NAME);
+ mDbName = extras == null ? null : extras.getString(Settings.EXTRA_DB_NAME);
try {
- final int appWidgetIdIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.APPWIDGET_ID);
- final int appWidgetProviderIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.APPWIDGET_PROVIDER);
- final int spanXIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.SPANY);
- final int rankIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.RANK);
- final int optionsIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.OPTIONS);
- final int sourceContainerIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.APPWIDGET_SOURCE);
-
final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
mUserManagerState.init(mUserCache, mUserManager);
@@ -425,437 +410,23 @@
unlockedUsers.put(serialNo, userUnlocked);
}
- WorkspaceItemInfo info;
- LauncherAppWidgetInfo appWidgetInfo;
- LauncherAppWidgetProviderInfo widgetProviderInfo;
- Intent intent;
- String targetPkg;
List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
while (!mStopped && c.moveToNext()) {
- try {
- if (c.user == null) {
- // User has been deleted, remove the item.
- c.markDeleted("User has been deleted");
- continue;
- }
-
- boolean allowMissingTarget = false;
- switch (c.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- intent = c.parseIntent();
- if (intent == null) {
- c.markDeleted("Invalid or null intent");
- continue;
- }
-
- int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
- ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
- ComponentName cn = intent.getComponent();
- targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
-
- if (TextUtils.isEmpty(targetPkg) &&
- c.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- c.markDeleted("Only legacy shortcuts can have null package");
- continue;
- }
-
- // If there is no target package, its an implicit intent
- // (legacy shortcut) which is always valid
- boolean validTarget = TextUtils.isEmpty(targetPkg) ||
- mLauncherApps.isPackageEnabled(targetPkg, c.user);
-
- // If it's a deep shortcut, we'll use pinned shortcuts to restore it
- if (cn != null && validTarget && c.itemType
- != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- // If the apk is present and the shortcut points to a specific
- // component.
-
- // If the component is already present
- if (mLauncherApps.isActivityEnabled(cn, c.user)) {
- // no special handling necessary for this item
- c.markRestored();
- } else {
- // Gracefully try to find a fallback activity.
- intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
- if (intent != null) {
- c.restoreFlag = 0;
- c.updater().put(
- LauncherSettings.Favorites.INTENT,
- intent.toUri(0)).commit();
- cn = intent.getComponent();
- } else {
- c.markDeleted("Unable to find a launch target");
- continue;
- }
- }
- }
- // else if cn == null => can't infer much, leave it
- // else if !validPkg => could be restored icon or missing sd-card
-
- if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
- // Points to a valid app (superset of cn != null) but the apk
- // is not available.
-
- if (c.restoreFlag != 0) {
- // Package is not yet available but might be
- // installed later.
- FileLog.d(TAG, "package not yet restored: " + targetPkg);
-
- tempPackageKey.update(targetPkg, c.user);
- if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
- // Restore has started once.
- } else if (installingPkgs.containsKey(tempPackageKey)) {
- // App restore has started. Update the flag
- c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
- c.updater().put(LauncherSettings.Favorites.RESTORED,
- c.restoreFlag).commit();
- } else {
- c.markDeleted("Unrestored app removed: " + targetPkg);
- continue;
- }
- } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
- // Package is present but not available.
- disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
- // Add the icon on the workspace anyway.
- allowMissingTarget = true;
- } else if (!isSdCardReady) {
- // SdCard is not ready yet. Package might get available,
- // once it is ready.
- Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
- mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
- // Add the icon on the workspace anyway.
- allowMissingTarget = true;
- } else {
- // Do not wait for external media load anymore.
- c.markDeleted("Invalid package removed: " + targetPkg);
- continue;
- }
- }
-
- if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
- validTarget = false;
- }
-
- if (validTarget) {
- // The shortcut points to a valid target (either no target
- // or something which is ready to be used)
- c.markRestored();
- }
-
- boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
-
- if (c.restoreFlag != 0) {
- // Already verified above that user is same as default user
- info = c.getRestoredItemInfo(intent);
- } else if (c.itemType ==
- LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = c.getAppShortcutInfo(
- intent,
- allowMissingTarget,
- useLowResIcon,
- !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get());
- } else if (c.itemType ==
- LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-
- ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
- if (unlockedUsers.get(c.serialNumber)) {
- ShortcutInfo pinnedShortcut =
- shortcutKeyToPinnedShortcuts.get(key);
- if (pinnedShortcut == null) {
- // The shortcut is no longer valid.
- c.markDeleted("Pinned shortcut not found");
- continue;
- }
- info = new WorkspaceItemInfo(pinnedShortcut, context);
- // If the pinned deep shortcut is no longer published,
- // use the last saved icon instead of the default.
- mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
-
- if (pmHelper.isAppSuspended(
- pinnedShortcut.getPackage(), info.user)) {
- info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
- }
- intent = info.getIntent();
- allDeepShortcuts.add(pinnedShortcut);
- } else {
- // Create a shortcut info in disabled mode for now.
- info = c.loadSimpleWorkspaceItem();
- info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
- }
- } else { // item type == ITEM_TYPE_SHORTCUT
- info = c.loadSimpleWorkspaceItem();
-
- // Shortcuts are only available on the primary profile
- if (!TextUtils.isEmpty(targetPkg)
- && pmHelper.isAppSuspended(targetPkg, c.user)) {
- disabledState |= FLAG_DISABLED_SUSPENDED;
- }
- info.options = c.getInt(optionsIndex);
-
- // App shortcuts that used to be automatically added to Launcher
- // didn't always have the correct intent flags set, so do that
- // here
- if (intent.getAction() != null &&
- intent.getCategories() != null &&
- intent.getAction().equals(Intent.ACTION_MAIN) &&
- intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- intent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
- }
-
- if (info != null) {
- if (info.itemType
- != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- // Skip deep shortcuts; their title and icons have already been
- // loaded above.
- iconRequestInfos.add(
- c.createIconRequestInfo(info, useLowResIcon));
- }
-
- c.applyCommonProperties(info);
-
- info.intent = intent;
- info.rank = c.getInt(rankIndex);
- info.spanX = 1;
- info.spanY = 1;
- info.runtimeStatusFlags |= disabledState;
- if (isSafeMode && !isSystemApp(context, intent)) {
- info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
- }
- LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
- if (activityInfo != null) {
- info.setProgressLevel(
- PackageManagerHelper
- .getLoadingProgress(activityInfo),
- PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
- }
-
- if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
- tempPackageKey.update(targetPkg, c.user);
- SessionInfo si = installingPkgs.get(tempPackageKey);
- if (si == null) {
- info.runtimeStatusFlags &=
- ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
- } else if (activityInfo == null) {
- int installProgress = (int) (si.getProgress() * 100);
-
- info.setProgressLevel(
- installProgress,
- PackageInstallInfo.STATUS_INSTALLING);
- }
- }
-
- c.checkAndAddItem(info, mBgDataModel, logger);
- } else {
- throw new RuntimeException("Unexpected null WorkspaceItemInfo");
- }
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
- c.applyCommonProperties(folderInfo);
-
- // Do not trim the folder label, as is was set by the user.
- folderInfo.title = c.getString(c.titleIndex);
- folderInfo.spanX = 1;
- folderInfo.spanY = 1;
- folderInfo.options = c.getInt(optionsIndex);
-
- // no special handling required for restored folders
- c.markRestored();
-
- c.checkAndAddItem(folderInfo, mBgDataModel, logger);
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- if (WidgetsModel.GO_DISABLE_WIDGETS) {
- c.markDeleted("Only legacy shortcuts can have null package");
- continue;
- }
- // Follow through
- case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
- // Read all Launcher-specific widget details
- boolean customWidget = c.itemType ==
- LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-
- int appWidgetId = c.getInt(appWidgetIdIndex);
- String savedProvider = c.getString(appWidgetProviderIndex);
- final ComponentName component;
-
- boolean isSearchWidget = (c.getInt(optionsIndex)
- & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0;
- if (isSearchWidget) {
- component = QsbContainerView.getSearchComponentName(context);
- if (component == null) {
- c.markDeleted("Discarding SearchWidget without packagename ");
- continue;
- }
- } else {
- component = ComponentName.unflattenFromString(savedProvider);
- }
- final boolean isIdValid = !c.hasRestoreFlag(
- LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
- final boolean wasProviderReady = !c.hasRestoreFlag(
- LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
-
- ComponentKey providerKey = new ComponentKey(component, c.user);
- if (!mWidgetProvidersMap.containsKey(providerKey)) {
- mWidgetProvidersMap.put(providerKey,
- widgetHelper.findProvider(component, c.user));
- }
- final AppWidgetProviderInfo provider =
- mWidgetProvidersMap.get(providerKey);
-
- final boolean isProviderReady = isValidProvider(provider);
- if (!isSafeMode && !customWidget &&
- wasProviderReady && !isProviderReady) {
- c.markDeleted(
- "Deleting widget that isn't installed anymore: "
- + provider);
- } else {
- if (isProviderReady) {
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- provider.provider);
-
- // The provider is available. So the widget is either
- // available or not available. We do not need to track
- // any future restore updates.
- int status = c.restoreFlag &
- ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED &
- ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
- if (!wasProviderReady) {
- // If provider was not previously ready, update the
- // status and UI flag.
-
- // Id would be valid only if the widget restore broadcast was received.
- if (isIdValid) {
- status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
- }
- }
- appWidgetInfo.restoreStatus = status;
- } else {
- Log.v(TAG, "Widget restore pending id=" + c.id
- + " appWidgetId=" + appWidgetId
- + " status =" + c.restoreFlag);
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- component);
- appWidgetInfo.restoreStatus = c.restoreFlag;
-
- tempPackageKey.update(component.getPackageName(), c.user);
- SessionInfo si =
- installingPkgs.get(tempPackageKey);
- Integer installProgress = si == null
- ? null
- : (int) (si.getProgress() * 100);
-
- if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
- // Restore has started once.
- } else if (installProgress != null) {
- // App restore has started. Update the flag
- appWidgetInfo.restoreStatus |=
- LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
- } else if (!isSafeMode) {
- c.markDeleted("Unrestored widget removed: " + component);
- continue;
- }
-
- appWidgetInfo.installProgress =
- installProgress == null ? 0 : installProgress;
- }
- if (appWidgetInfo.hasRestoreFlag(
- LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
- appWidgetInfo.bindOptions = c.parseIntent();
- }
-
- c.applyCommonProperties(appWidgetInfo);
- appWidgetInfo.spanX = c.getInt(spanXIndex);
- appWidgetInfo.spanY = c.getInt(spanYIndex);
- appWidgetInfo.options = c.getInt(optionsIndex);
- appWidgetInfo.user = c.user;
- appWidgetInfo.sourceContainer = c.getInt(sourceContainerIndex);
-
- if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
- c.markDeleted("Widget has invalid size: "
- + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
- continue;
- }
- widgetProviderInfo =
- widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
- if (widgetProviderInfo != null
- && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
- || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
- FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
- + " minSizes not meet: span=" + appWidgetInfo.spanX
- + "x" + appWidgetInfo.spanY + " minSpan="
- + widgetProviderInfo.minSpanX + "x"
- + widgetProviderInfo.minSpanY);
- logWidgetInfo(mApp.getInvariantDeviceProfile(),
- widgetProviderInfo);
- }
- if (!c.isOnWorkspaceOrHotseat()) {
- c.markDeleted("Widget found where container != " +
- "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
- continue;
- }
-
- if (!customWidget) {
- String providerName =
- appWidgetInfo.providerName.flattenToString();
- if (!providerName.equals(savedProvider) ||
- (appWidgetInfo.restoreStatus != c.restoreFlag)) {
- c.updater()
- .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
- providerName)
- .put(LauncherSettings.Favorites.RESTORED,
- appWidgetInfo.restoreStatus)
- .commit();
- }
- }
-
- if (appWidgetInfo.restoreStatus !=
- LauncherAppWidgetInfo.RESTORE_COMPLETED) {
- appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
- mApp.getContext(),
- appWidgetInfo.providerName,
- appWidgetInfo.user);
- mIconCache.getTitleAndIconForApp(
- appWidgetInfo.pendingItemInfo, false);
- }
-
- c.checkAndAddItem(appWidgetInfo, mBgDataModel);
- }
- break;
- }
- } catch (Exception e) {
- Log.e(TAG, "Desktop items loading interrupted", e);
- }
+ processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady,
+ tempPackageKey, widgetHelper, pmHelper, shortcutKeyToPinnedShortcuts,
+ iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts);
}
- if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) {
- Trace.beginSection("LoadWorkspaceIconsInBulk");
- try {
- mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
- for (IconRequestInfo<WorkspaceItemInfo> iconRequestInfo :
- iconRequestInfos) {
- WorkspaceItemInfo wai = iconRequestInfo.itemInfo;
- if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
- iconRequestInfo.loadWorkspaceIcon(mApp.getContext());
- }
- }
- } finally {
- Trace.endSection();
- }
- }
+ maybeLoadWorkspaceIconsInBulk(iconRequestInfos);
} finally {
IOUtils.closeSilently(c);
}
// Load delegate items
- mModelDelegate.loadItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+ mModelDelegate.loadHotseatItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+ mModelDelegate.loadAllAppsItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+ mModelDelegate.loadWidgetsRecommendationItems();
+ mModelDelegate.markActive();
// Load string cache
mModelDelegate.loadStringCache(mBgDataModel.stringCache);
@@ -885,7 +456,7 @@
info.rank = rank;
if (info.usingLowResIcon()
- && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && info.itemType == Favorites.ITEM_TYPE_APPLICATION
&& verifier.isItemInPreview(info.rank)) {
mIconCache.getTitleAndIcon(info, false);
}
@@ -896,6 +467,418 @@
}
}
+ private void processWorkspaceItem(LoaderCursor c,
+ LoaderMemoryLogger memoryLogger,
+ HashMap<PackageUserKey, SessionInfo> installingPkgs,
+ boolean isSdCardReady,
+ PackageUserKey tempPackageKey,
+ WidgetManagerHelper widgetHelper,
+ PackageManagerHelper pmHelper,
+ Map<ShortcutKey, ShortcutInfo> shortcutKeyToPinnedShortcuts,
+ List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos,
+ LongSparseArray<Boolean> unlockedUsers,
+ boolean isSafeMode,
+ List<ShortcutInfo> allDeepShortcuts) {
+
+ try {
+ if (c.user == null) {
+ // User has been deleted, remove the item.
+ c.markDeleted("User has been deleted");
+ return;
+ }
+
+ boolean allowMissingTarget = false;
+ switch (c.itemType) {
+ case Favorites.ITEM_TYPE_SHORTCUT:
+ case Favorites.ITEM_TYPE_APPLICATION:
+ case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+ Intent intent = c.parseIntent();
+ if (intent == null) {
+ c.markDeleted("Invalid or null intent");
+ return;
+ }
+
+ int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
+ ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
+ ComponentName cn = intent.getComponent();
+ String targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
+
+ if (TextUtils.isEmpty(targetPkg)
+ && c.itemType != Favorites.ITEM_TYPE_SHORTCUT) {
+ c.markDeleted("Only legacy shortcuts can have null package");
+ return;
+ }
+
+ // If there is no target package, it's an implicit intent
+ // (legacy shortcut) which is always valid
+ boolean validTarget = TextUtils.isEmpty(targetPkg)
+ || mLauncherApps.isPackageEnabled(targetPkg, c.user);
+
+ // If it's a deep shortcut, we'll use pinned shortcuts to restore it
+ if (cn != null && validTarget && c.itemType
+ != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ // If the apk is present and the shortcut points to a specific component.
+
+ // If the component is already present
+ if (mLauncherApps.isActivityEnabled(cn, c.user)) {
+ // no special handling necessary for this item
+ c.markRestored();
+ } else {
+ // Gracefully try to find a fallback activity.
+ intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
+ if (intent != null) {
+ c.restoreFlag = 0;
+ c.updater().put(
+ Favorites.INTENT,
+ intent.toUri(0)).commit();
+ cn = intent.getComponent();
+ } else {
+ c.markDeleted("Unable to find a launch target");
+ return;
+ }
+ }
+ }
+ // else if cn == null => can't infer much, leave it
+ // else if !validPkg => could be restored icon or missing sd-card
+
+ if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
+ // Points to a valid app (superset of cn != null) but the apk
+ // is not available.
+
+ if (c.restoreFlag != 0) {
+ // Package is not yet available but might be
+ // installed later.
+ FileLog.d(TAG, "package not yet restored: " + targetPkg);
+
+ tempPackageKey.update(targetPkg, c.user);
+ if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
+ // Restore has started once.
+ } else if (installingPkgs.containsKey(tempPackageKey)) {
+ // App restore has started. Update the flag
+ c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
+ c.updater().put(Favorites.RESTORED,
+ c.restoreFlag).commit();
+ } else {
+ c.markDeleted("Unrestored app removed: " + targetPkg);
+ return;
+ }
+ } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
+ // Package is present but not available.
+ disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
+ // Add the icon on the workspace anyway.
+ allowMissingTarget = true;
+ } else if (!isSdCardReady) {
+ // SdCard is not ready yet. Package might get available,
+ // once it is ready.
+ Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
+ mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
+ // Add the icon on the workspace anyway.
+ allowMissingTarget = true;
+ } else {
+ // Do not wait for external media load anymore.
+ c.markDeleted("Invalid package removed: " + targetPkg);
+ return;
+ }
+ }
+
+ if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
+ validTarget = false;
+ }
+
+ if (validTarget) {
+ // The shortcut points to a valid target (either no target
+ // or something which is ready to be used)
+ c.markRestored();
+ }
+
+ boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
+
+ WorkspaceItemInfo info;
+ if (c.restoreFlag != 0) {
+ // Already verified above that user is same as default user
+ info = c.getRestoredItemInfo(intent);
+ } else if (c.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+ info = c.getAppShortcutInfo(intent, allowMissingTarget, useLowResIcon,
+ !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get());
+ } else if (c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
+ if (unlockedUsers.get(c.serialNumber)) {
+ ShortcutInfo pinnedShortcut = shortcutKeyToPinnedShortcuts.get(key);
+ if (pinnedShortcut == null) {
+ // The shortcut is no longer valid.
+ c.markDeleted("Pinned shortcut not found");
+ return;
+ }
+ info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
+ // If the pinned deep shortcut is no longer published,
+ // use the last saved icon instead of the default.
+ mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
+
+ if (pmHelper.isAppSuspended(
+ pinnedShortcut.getPackage(), info.user)) {
+ info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
+ }
+ intent = info.getIntent();
+ allDeepShortcuts.add(pinnedShortcut);
+ } else {
+ // Create a shortcut info in disabled mode for now.
+ info = c.loadSimpleWorkspaceItem();
+ info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
+ }
+ } else { // item type == ITEM_TYPE_SHORTCUT
+ info = c.loadSimpleWorkspaceItem();
+
+ // Shortcuts are only available on the primary profile
+ if (!TextUtils.isEmpty(targetPkg)
+ && pmHelper.isAppSuspended(targetPkg, c.user)) {
+ disabledState |= FLAG_DISABLED_SUSPENDED;
+ }
+ info.options = c.getOptions();
+
+ // App shortcuts that used to be automatically added to Launcher
+ // didn't always have the correct intent flags set, so do that here
+ if (intent.getAction() != null
+ && intent.getCategories() != null
+ && intent.getAction().equals(Intent.ACTION_MAIN)
+ && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
+ }
+
+ if (info != null) {
+ if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ // Skip deep shortcuts; their title and icons have already been
+ // loaded above.
+ iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
+ }
+
+ c.applyCommonProperties(info);
+
+ info.intent = intent;
+ info.rank = c.getRank();
+ info.spanX = 1;
+ info.spanY = 1;
+ info.runtimeStatusFlags |= disabledState;
+ if (isSafeMode && !isSystemApp(mApp.getContext(), intent)) {
+ info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
+ }
+ LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
+ if (activityInfo != null) {
+ info.setProgressLevel(
+ PackageManagerHelper.getLoadingProgress(activityInfo),
+ PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+ }
+
+ if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
+ tempPackageKey.update(targetPkg, c.user);
+ SessionInfo si = installingPkgs.get(tempPackageKey);
+ if (si == null) {
+ info.runtimeStatusFlags
+ &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+ } else if (activityInfo == null) {
+ int installProgress = (int) (si.getProgress() * 100);
+
+ info.setProgressLevel(installProgress,
+ PackageInstallInfo.STATUS_INSTALLING);
+ }
+ }
+
+ c.checkAndAddItem(info, mBgDataModel, memoryLogger);
+ } else {
+ throw new RuntimeException("Unexpected null WorkspaceItemInfo");
+ }
+ break;
+
+ case Favorites.ITEM_TYPE_FOLDER:
+ FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
+ c.applyCommonProperties(folderInfo);
+
+ // Do not trim the folder label, as is was set by the user.
+ folderInfo.title = c.getString(c.mTitleIndex);
+ folderInfo.spanX = 1;
+ folderInfo.spanY = 1;
+ folderInfo.options = c.getOptions();
+
+ // no special handling required for restored folders
+ c.markRestored();
+
+ c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger);
+ break;
+
+ case Favorites.ITEM_TYPE_APPWIDGET:
+ if (WidgetsModel.GO_DISABLE_WIDGETS) {
+ c.markDeleted("Only legacy shortcuts can have null package");
+ return;
+ }
+ // Follow through
+ case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+ // Read all Launcher-specific widget details
+ boolean customWidget = c.itemType
+ == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+
+ int appWidgetId = c.getAppWidgetId();
+ String savedProvider = c.getAppWidgetProvider();
+ final ComponentName component;
+
+ if ((c.getOptions() & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0) {
+ component = QsbContainerView.getSearchComponentName(mApp.getContext());
+ if (component == null) {
+ c.markDeleted("Discarding SearchWidget without packagename ");
+ return;
+ }
+ } else {
+ component = ComponentName.unflattenFromString(savedProvider);
+ }
+ final boolean isIdValid =
+ !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
+ final boolean wasProviderReady =
+ !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
+
+ ComponentKey providerKey = new ComponentKey(component, c.user);
+ if (!mWidgetProvidersMap.containsKey(providerKey)) {
+ mWidgetProvidersMap.put(providerKey,
+ widgetHelper.findProvider(component, c.user));
+ }
+ final AppWidgetProviderInfo provider = mWidgetProvidersMap.get(providerKey);
+
+ final boolean isProviderReady = isValidProvider(provider);
+ if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) {
+ c.markDeleted("Deleting widget that isn't installed anymore: " + provider);
+ } else {
+ LauncherAppWidgetInfo appWidgetInfo;
+ if (isProviderReady) {
+ appWidgetInfo =
+ new LauncherAppWidgetInfo(appWidgetId, provider.provider);
+
+ // The provider is available. So the widget is either
+ // available or not available. We do not need to track
+ // any future restore updates.
+ int status = c.restoreFlag
+ & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+ & ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
+ if (!wasProviderReady) {
+ // If provider was not previously ready, update status and UI flag.
+
+ // Id would be valid only if the widget restore broadcast received.
+ if (isIdValid) {
+ status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+ }
+ }
+ appWidgetInfo.restoreStatus = status;
+ } else {
+ Log.v(TAG, "Widget restore pending id=" + c.id
+ + " appWidgetId=" + appWidgetId
+ + " status =" + c.restoreFlag);
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component);
+ appWidgetInfo.restoreStatus = c.restoreFlag;
+
+ tempPackageKey.update(component.getPackageName(), c.user);
+ SessionInfo si = installingPkgs.get(tempPackageKey);
+ Integer installProgress = si == null
+ ? null
+ : (int) (si.getProgress() * 100);
+
+ if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
+ // Restore has started once.
+ } else if (installProgress != null) {
+ // App restore has started. Update the flag
+ appWidgetInfo.restoreStatus
+ |= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+ } else if (!isSafeMode) {
+ c.markDeleted("Unrestored widget removed: " + component);
+ return;
+ }
+
+ appWidgetInfo.installProgress =
+ installProgress == null ? 0 : installProgress;
+ }
+ if (appWidgetInfo.hasRestoreFlag(
+ LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
+ appWidgetInfo.bindOptions = c.parseIntent();
+ }
+
+ c.applyCommonProperties(appWidgetInfo);
+ appWidgetInfo.spanX = c.getSpanX();
+ appWidgetInfo.spanY = c.getSpanY();
+ appWidgetInfo.options = c.getOptions();
+ appWidgetInfo.user = c.user;
+ appWidgetInfo.sourceContainer = c.getAppWidgetSource();
+
+ if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
+ c.markDeleted("Widget has invalid size: "
+ + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
+ return;
+ }
+ LauncherAppWidgetProviderInfo widgetProviderInfo =
+ widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
+ if (widgetProviderInfo != null
+ && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
+ || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
+ FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
+ + " minSizes not meet: span=" + appWidgetInfo.spanX
+ + "x" + appWidgetInfo.spanY + " minSpan="
+ + widgetProviderInfo.minSpanX + "x"
+ + widgetProviderInfo.minSpanY);
+ logWidgetInfo(mApp.getInvariantDeviceProfile(),
+ widgetProviderInfo);
+ }
+ if (!c.isOnWorkspaceOrHotseat()) {
+ c.markDeleted("Widget found where container != CONTAINER_DESKTOP"
+ + "nor CONTAINER_HOTSEAT - ignoring!");
+ return;
+ }
+
+ if (!customWidget) {
+ String providerName = appWidgetInfo.providerName.flattenToString();
+ if (!providerName.equals(savedProvider)
+ || (appWidgetInfo.restoreStatus != c.restoreFlag)) {
+ c.updater()
+ .put(Favorites.APPWIDGET_PROVIDER,
+ providerName)
+ .put(Favorites.RESTORED,
+ appWidgetInfo.restoreStatus)
+ .commit();
+ }
+ }
+
+ if (appWidgetInfo.restoreStatus
+ != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+ appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
+ mApp.getContext(),
+ appWidgetInfo.providerName,
+ appWidgetInfo.user);
+ mIconCache.getTitleAndIconForApp(
+ appWidgetInfo.pendingItemInfo, false);
+ }
+
+ c.checkAndAddItem(appWidgetInfo, mBgDataModel);
+ }
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Desktop items loading interrupted", e);
+ }
+ }
+
+ private void maybeLoadWorkspaceIconsInBulk(
+ List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos) {
+ if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) {
+ Trace.beginSection("LoadWorkspaceIconsInBulk");
+ try {
+ mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
+ for (IconRequestInfo<WorkspaceItemInfo> iconRequestInfo : iconRequestInfos) {
+ WorkspaceItemInfo wai = iconRequestInfo.itemInfo;
+ if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
+ iconRequestInfo.loadWorkspaceIcon(mApp.getContext());
+ }
+ }
+ } finally {
+ Trace.endSection();
+ }
+ }
+ }
+
private void setIgnorePackages(IconCacheUpdateHandler updateHandler) {
// Ignore packages which have a promise icon.
synchronized (mBgDataModel) {
@@ -917,15 +900,12 @@
}
}
- private void sanitizeData() {
- Context context = mApp.getContext();
- ContentResolver contentResolver = context.getContentResolver();
- if (mItemsDeleted) {
+ private void sanitizeFolders(boolean itemsDeleted) {
+ if (itemsDeleted) {
// Remove any empty folder
- int[] deletedFolderIds = LauncherSettings.Settings
- .call(contentResolver,
- LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
- .getIntArray(LauncherSettings.Settings.EXTRA_VALUE);
+ int[] deletedFolderIds = Settings.call(mApp.getContext().getContentResolver(),
+ Settings.METHOD_DELETE_EMPTY_FOLDERS)
+ .getIntArray(Settings.EXTRA_VALUE);
synchronized (mBgDataModel) {
for (int folderId : deletedFolderIds) {
mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
@@ -933,11 +913,16 @@
mBgDataModel.itemsIdMap.remove(folderId);
}
}
-
}
+ }
+
+ private void sanitizeWidgetsShortcutsAndPackages() {
+ Context context = mApp.getContext();
+ ContentResolver contentResolver = context.getContentResolver();
+
// Remove any ghost widgets
- LauncherSettings.Settings.call(contentResolver,
- LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
+ Settings.call(contentResolver,
+ Settings.METHOD_REMOVE_GHOST_WIDGETS);
// Update pinned state of model shortcuts
mBgDataModel.updateShortcutPinnedState(context);
@@ -1107,10 +1092,12 @@
FileLog.d(TAG, widgetDimension.toString());
}
- private static void logASplit(final TimingLogger logger, final String label) {
- logger.addSplit(label);
- if (DEBUG) {
- Log.d(TAG, label);
+ private static void logASplit(@Nullable TimingLogger timingLogger, String label) {
+ if (timingLogger != null) {
+ timingLogger.addSplit(label);
+ if (DEBUG) {
+ Log.d(TAG, label);
+ }
}
}
}
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 3bd9470..0639a6c 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -80,10 +80,29 @@
}
/**
- * Load delegate items if any in the data model
+ * Load hot seat items if any in the data model
*/
@WorkerThread
- public void loadItems(UserManagerState ums, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+ public void loadHotseatItems(UserManagerState ums,
+ Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+
+ /**
+ * Load all apps items if any in the data model
+ */
+ @WorkerThread
+ public void loadAllAppsItems(UserManagerState ums,
+ Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+
+ /**
+ * Load widget recommendation items if any in the data model
+ */
+ @WorkerThread
+ public void loadWidgetsRecommendationItems() { }
+
+ /**
+ * Marks the ModelDelegate as active
+ */
+ public void markActive() { }
/**
* Load String cache
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index db23566..7ca3b11 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -171,15 +171,22 @@
}
return null;
}
- String pkg = sessionInfo.getInstallerPackageName();
+ return isTrustedPackage(sessionInfo.getInstallerPackageName(), getUserHandle(sessionInfo))
+ ? sessionInfo : null;
+ }
+
+ /**
+ * Returns true if the provided packageName can be trusted for user configurations
+ */
+ public boolean isTrustedPackage(String pkg, UserHandle user) {
synchronized (mSessionVerifiedMap) {
if (!mSessionVerifiedMap.containsKey(pkg)) {
boolean hasSystemFlag = new PackageManagerHelper(mAppContext).getApplicationInfo(
- pkg, getUserHandle(sessionInfo), ApplicationInfo.FLAG_SYSTEM) != null;
+ pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag);
}
}
- return mSessionVerifiedMap.get(pkg) ? sessionInfo : null;
+ return mSessionVerifiedMap.get(pkg);
}
@NonNull
diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
index 7af14c6..14e67b2 100644
--- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
@@ -112,26 +111,6 @@
return true;
}
- static class ShortcutConfigActivityInfoVL extends ShortcutConfigActivityInfo {
-
- private final ActivityInfo mInfo;
-
- ShortcutConfigActivityInfoVL(ActivityInfo info) {
- super(new ComponentName(info.packageName, info.name), Process.myUserHandle());
- mInfo = info;
- }
-
- @Override
- public CharSequence getLabel(PackageManager pm) {
- return mInfo.loadLabel(pm);
- }
-
- @Override
- public Drawable getFullResIcon(IconCache cache) {
- return cache.getFullResIcon(mInfo);
- }
- }
-
@TargetApi(26)
public static class ShortcutConfigActivityInfoVO extends ShortcutConfigActivityInfo {
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 9a745ab..a0f21dc 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -20,7 +20,10 @@
import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE;
import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -36,11 +39,13 @@
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.util.Pair;
+import android.util.Property;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -80,6 +85,19 @@
protected int CLOSE_CHILD_FADE_START_DELAY = 0;
protected int CLOSE_CHILD_FADE_DURATION = 140;
+ private static final int OPEN_DURATION_U = 200;
+ private static final int OPEN_FADE_START_DELAY_U = 0;
+ private static final int OPEN_FADE_DURATION_U = 83;
+ private static final int OPEN_CHILD_FADE_START_DELAY_U = 0;
+ private static final int OPEN_CHILD_FADE_DURATION_U = 83;
+ private static final int OPEN_OVERSHOOT_DURATION_U = 200;
+
+ private static final int CLOSE_DURATION_U = 233;
+ private static final int CLOSE_FADE_START_DELAY_U = 150;
+ private static final int CLOSE_FADE_DURATION_U = 83;
+ private static final int CLOSE_CHILD_FADE_START_DELAY_U = 150;
+ private static final int CLOSE_CHILD_FADE_DURATION_U = 83;
+
protected final Rect mTempRect = new Rect();
protected final LayoutInflater mInflater;
@@ -103,6 +121,7 @@
protected AnimatorSet mOpenCloseAnimator;
protected boolean mDeferContainerRemoval;
protected boolean shouldScaleArrow = false;
+ protected boolean mIsArrowRotated = false;
private final GradientDrawable mRoundedTop;
private final GradientDrawable mRoundedBottom;
@@ -116,7 +135,7 @@
private final String mIterateChildrenTag;
- private final int[] mColorIds;
+ protected final int[] mColorIds;
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -125,8 +144,8 @@
mActivityContext = ActivityContext.lookupContext(context);
mIsRtl = Utilities.isRtl(getResources());
- int backgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
- mArrowColor = backgroundColor;
+ int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
+ mArrowColor = popupPrimaryColor;
mElevation = getResources().getDimension(R.dimen.deep_shortcuts_elevation);
// Initialize arrow view
@@ -143,18 +162,18 @@
int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius);
mRoundedTop = new GradientDrawable();
- mRoundedTop.setColor(backgroundColor);
+ mRoundedTop.setColor(popupPrimaryColor);
mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
mRoundedBottom = new GradientDrawable();
- mRoundedBottom.setColor(backgroundColor);
+ mRoundedBottom.setColor(popupPrimaryColor);
mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
- if (mActivityContext.shouldUseColorExtractionForPopup()) {
+ if (!ENABLE_MATERIAL_U_POPUP.get() && mActivityContext.canUseMultipleShadesForPopup()) {
mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
R.color.popup_shade_third};
} else {
@@ -241,15 +260,23 @@
mlp.bottomMargin = 0;
if (colors != null) {
- backgroundColor = colors[numVisibleChild % colors.length];
+ if (!ENABLE_MATERIAL_U_POPUP.get()) {
+ backgroundColor = colors[numVisibleChild % colors.length];
+ }
+
+ if (ENABLE_MATERIAL_U_POPUP.get() && isShortcutContainer(view)) {
+ setChildColor(view, colors[0], colorAnimator);
+ mArrowColor = colors[0];
+ }
}
// Arrow color matches the first child or the last child.
- if (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this)) {
+ if (!ENABLE_MATERIAL_U_POPUP.get()
+ && (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this))) {
mArrowColor = backgroundColor;
}
- if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) {
+ if (view instanceof ViewGroup && isShortcutContainer(view)) {
assignMarginsAndBackgrounds((ViewGroup) view, backgroundColor);
numVisibleChild++;
continue;
@@ -287,6 +314,13 @@
}
/**
+ * Returns {@code true} if view is a layout container of shortcuts
+ */
+ boolean isShortcutContainer(View view) {
+ return mIterateChildrenTag.equals(view.getTag());
+ }
+
+ /**
* Sets the background color of the child.
*/
protected void setChildColor(View view, int color, AnimatorSet animatorSetOut) {
@@ -308,7 +342,7 @@
*/
protected void reorderAndShow(int viewsToFlip) {
setupForDisplay();
- boolean reverseOrder = mIsAboveIcon;
+ boolean reverseOrder = !ENABLE_MATERIAL_U_POPUP.get() && mIsAboveIcon;
if (reverseOrder) {
reverseOrder(viewsToFlip);
}
@@ -575,10 +609,24 @@
protected void animateOpen() {
setVisibility(View.VISIBLE);
+ mOpenCloseAnimator = ENABLE_MATERIAL_U_POPUP.get()
+ ? getMaterialUOpenCloseAnimator(
+ true,
+ OPEN_DURATION_U,
+ OPEN_FADE_START_DELAY_U,
+ OPEN_FADE_DURATION_U,
+ OPEN_CHILD_FADE_START_DELAY_U,
+ OPEN_CHILD_FADE_DURATION_U,
+ EMPHASIZED_DECELERATE)
+ : getOpenCloseAnimator(
+ true,
+ OPEN_DURATION,
+ OPEN_FADE_START_DELAY,
+ OPEN_FADE_DURATION,
+ OPEN_CHILD_FADE_START_DELAY,
+ OPEN_CHILD_FADE_DURATION,
+ DECELERATED_EASE);
- mOpenCloseAnimator = getOpenCloseAnimator(true, OPEN_DURATION, OPEN_FADE_START_DELAY,
- OPEN_FADE_DURATION, OPEN_CHILD_FADE_START_DELAY, OPEN_CHILD_FADE_DURATION,
- DECELERATED_EASE);
onCreateOpenAnimation(mOpenCloseAnimator);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -634,7 +682,7 @@
for (int i = group.getChildCount() - 1; i >= 0; --i) {
View view = group.getChildAt(i);
if (view.getVisibility() == VISIBLE && view instanceof ViewGroup) {
- if (mIterateChildrenTag.equals(view.getTag())) {
+ if (isShortcutContainer(view)) {
fadeInChildViews((ViewGroup) view, alphaValues, startDelay, duration, out);
continue;
}
@@ -664,6 +712,24 @@
mOpenCloseAnimator = getOpenCloseAnimator(false, CLOSE_DURATION, CLOSE_FADE_START_DELAY,
CLOSE_FADE_DURATION, CLOSE_CHILD_FADE_START_DELAY, CLOSE_CHILD_FADE_DURATION,
ACCELERATED_EASE);
+
+ mOpenCloseAnimator = ENABLE_MATERIAL_U_POPUP.get()
+ ? getMaterialUOpenCloseAnimator(
+ false,
+ CLOSE_DURATION_U,
+ CLOSE_FADE_START_DELAY_U,
+ CLOSE_FADE_DURATION_U,
+ CLOSE_CHILD_FADE_START_DELAY_U,
+ CLOSE_CHILD_FADE_DURATION_U,
+ EMPHASIZED_ACCELERATE)
+ : getOpenCloseAnimator(false,
+ CLOSE_DURATION,
+ CLOSE_FADE_START_DELAY,
+ CLOSE_FADE_DURATION,
+ CLOSE_CHILD_FADE_START_DELAY,
+ CLOSE_CHILD_FADE_DURATION,
+ ACCELERATED_EASE);
+
onCreateCloseAnimation(mOpenCloseAnimator);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -679,6 +745,59 @@
mOpenCloseAnimator.start();
}
+ protected AnimatorSet getMaterialUOpenCloseAnimator(boolean isOpening, int scaleDuration,
+ int fadeStartDelay, int fadeDuration, int childFadeStartDelay, int childFadeDuration,
+ Interpolator interpolator) {
+
+ int arrowCenter = mArrowOffsetHorizontal + mArrowWidth / 2;
+ if (mIsArrowRotated) {
+ setPivotX(mIsLeftAligned ? 0f : getMeasuredWidth());
+ setPivotY(arrowCenter);
+ } else {
+ setPivotX(mIsLeftAligned ? arrowCenter : getMeasuredWidth() - arrowCenter);
+ setPivotY(mIsAboveIcon ? getMeasuredHeight() : 0f);
+ }
+
+ float[] alphaValues = isOpening ? new float[] {0, 1} : new float[] {1, 0};
+ float[] scaleValues = isOpening ? new float[] {0.5f, 1.02f} : new float[] {1f, 0.5f};
+ Animator alpha = getAnimatorOfFloat(this, View.ALPHA, fadeDuration, fadeStartDelay,
+ LINEAR, alphaValues);
+ Animator arrowAlpha = getAnimatorOfFloat(mArrow, View.ALPHA, fadeDuration, fadeStartDelay,
+ LINEAR, alphaValues);
+ Animator scaleY = getAnimatorOfFloat(this, View.SCALE_Y, scaleDuration, 0, interpolator,
+ scaleValues);
+ Animator scaleX = getAnimatorOfFloat(this, View.SCALE_X, scaleDuration, 0, interpolator,
+ scaleValues);
+
+ final AnimatorSet animatorSet = new AnimatorSet();
+ if (isOpening) {
+ float[] scaleValuesOvershoot = new float[] {1.02f, 1f};
+ PathInterpolator overshootInterpolator = new PathInterpolator(0.3f, 0, 0.33f, 1f);
+ Animator overshootY = getAnimatorOfFloat(this, View.SCALE_Y,
+ OPEN_OVERSHOOT_DURATION_U, scaleDuration, overshootInterpolator,
+ scaleValuesOvershoot);
+ Animator overshootX = getAnimatorOfFloat(this, View.SCALE_X,
+ OPEN_OVERSHOOT_DURATION_U, scaleDuration, overshootInterpolator,
+ scaleValuesOvershoot);
+
+ animatorSet.playTogether(alpha, arrowAlpha, scaleY, scaleX, overshootX, overshootY);
+ } else {
+ animatorSet.playTogether(alpha, arrowAlpha, scaleY, scaleX);
+ }
+
+ fadeInChildViews(this, alphaValues, childFadeStartDelay, childFadeDuration, animatorSet);
+ return animatorSet;
+ }
+
+ private Animator getAnimatorOfFloat(View view, Property<View, Float> property,
+ int duration, int startDelay, Interpolator interpolator, float... values) {
+ Animator animator = ObjectAnimator.ofFloat(view, property, values);
+ animator.setDuration(duration);
+ animator.setInterpolator(interpolator);
+ animator.setStartDelay(startDelay);
+ return animator;
+ }
+
/**
* Called when creating the open transition allowing subclass can add additional animations.
*/
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 4da588e..8fef5c6 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -17,12 +17,16 @@
package com.android.launcher3.popup;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
+import static com.android.launcher3.Utilities.ATLEAST_P;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static java.util.Collections.emptyList;
+
import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.annotation.TargetApi;
@@ -39,6 +43,8 @@
import android.view.ViewGroup;
import android.widget.ImageView;
+import androidx.annotation.LayoutRes;
+
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
@@ -82,20 +88,20 @@
public class PopupContainerWithArrow<T extends Context & ActivityContext>
extends ArrowPopup<T> implements DragSource, DragController.DragListener {
- private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
+ private final List<DeepShortcutView> mDeepShortcuts = new ArrayList<>();
private final PointF mInterceptTouchDown = new PointF();
private final int mStartDragThreshold;
+ private static final int SHORTCUT_COLLAPSE_THRESHOLD = 6;
+
private BubbleTextView mOriginalIcon;
private int mNumNotifications;
private NotificationContainer mNotificationContainer;
private int mContainerWidth;
private ViewGroup mWidgetContainer;
-
private ViewGroup mDeepShortcutContainer;
-
private ViewGroup mSystemShortcutContainer;
protected PopupItemDragHandler mPopupItemDragHandler;
@@ -211,19 +217,27 @@
return null;
}
- final PopupContainerWithArrow<Launcher> container =
- (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
- R.layout.popup_container, launcher.getDragLayer(), false);
- container.configureForLauncher(launcher);
-
+ PopupContainerWithArrow<Launcher> container;
PopupDataProvider popupDataProvider = launcher.getPopupDataProvider();
- container.populateAndShow(icon,
- popupDataProvider.getShortcutCountForItem(item),
- popupDataProvider.getNotificationKeysForItem(item),
- launcher.getSupportedShortcuts()
- .map(s -> s.getShortcut(launcher, item, icon))
- .filter(Objects::nonNull)
- .collect(Collectors.toList()));
+ int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
+ List<SystemShortcut> systemShortcuts = launcher.getSupportedShortcuts()
+ .map(s -> s.getShortcut(launcher, item, icon))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ if (ENABLE_MATERIAL_U_POPUP.get()) {
+ container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
+ R.layout.popup_container_material_u, launcher.getDragLayer(), false);
+ container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
+ } else {
+ container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
+ R.layout.popup_container, launcher.getDragLayer(), false);
+ container.populateAndShow(
+ icon,
+ deepShortcutCount,
+ popupDataProvider.getNotificationKeysForItem(item),
+ systemShortcuts);
+ }
+ container.configureForLauncher(launcher);
launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
container.requestFocus();
return container;
@@ -246,7 +260,7 @@
initializeSystemShortcut(R.layout.system_shortcut, this, shortcuts.get(0));
return;
}
- mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
+ mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons_container, this);
for (SystemShortcut shortcut : shortcuts) {
initializeSystemShortcut(
R.layout.system_shortcut_icon_only, mSystemShortcutContainer,
@@ -281,17 +295,7 @@
mDeepShortcutContainer = findViewById(R.id.deep_shortcuts_container);
}
if (hasDeepShortcuts) {
- // Remove the widget shortcut fom the list
- List<SystemShortcut> systemShortcuts = shortcuts
- .stream()
- .filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
- .collect(Collectors.toList());
- Optional<SystemShortcut.Widgets> widgetShortcutOpt = shortcuts
- .stream()
- .filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
- .map(SystemShortcut.Widgets.class::cast)
- .findFirst();
-
+ List<SystemShortcut> systemShortcuts = getNonWidgetSystemShortcuts(shortcuts);
// if there are deep shortcuts, we might want to increase the width of shortcuts to fit
// horizontally laid out system shortcuts.
mContainerWidth = Math.max(mContainerWidth,
@@ -304,10 +308,10 @@
for (int i = shortcutCount; i > 0; i--) {
DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut, mDeepShortcutContainer);
v.getLayoutParams().width = mContainerWidth;
- mShortcuts.add(v);
+ mDeepShortcuts.add(v);
}
updateHiddenShortcuts();
-
+ Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(shortcuts);
if (widgetShortcutOpt.isPresent()) {
if (mWidgetContainer == null) {
mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
@@ -327,21 +331,151 @@
}
reorderAndShow(viewsToFlip);
+ showPopupContainer((ItemInfo) originalIcon.getTag(), notificationKeys);
+ }
- ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- setAccessibilityPaneTitle(getTitleForAccessibility());
+ /**
+ * Populate and show shortcuts for the Launcher U app shortcut design.
+ * Will inflate the container and shortcut View instances for the popup container.
+ * @param originalIcon App icon that the popup is shown for
+ * @param deepShortcutCount Number of DeepShortcutView instances to add to container
+ * @param systemShortcuts List of SystemShortcuts to add to container
+ */
+ public void populateAndShowRowsMaterialU(final BubbleTextView originalIcon,
+ int deepShortcutCount, List<SystemShortcut> systemShortcuts) {
+
+ mOriginalIcon = originalIcon;
+ mContainerWidth = getResources().getDimensionPixelSize(R.dimen.bg_popup_item_width);
+
+ if (deepShortcutCount > 0) {
+ addAllShortcutsMaterialU(deepShortcutCount, systemShortcuts);
+ } else if (!systemShortcuts.isEmpty()) {
+ addSystemShortcutsMaterialU(systemShortcuts,
+ R.layout.system_shortcut_rows_container_material_u,
+ R.layout.system_shortcut);
}
- mOriginalIcon.setForceHideDot(true);
+ // no reversing needed for U design
+ reorderAndShow(0);
+ showPopupContainer((ItemInfo) originalIcon.getTag(), /* notificationKeys= */ emptyList());
+ }
+ /**
+ * Animates and loads shortcuts on background thread for this popup container
+ */
+ private void showPopupContainer(ItemInfo originalItemInfo,
+ List<NotificationKeyData> notificationKeys) {
+
+ if (ATLEAST_P) {
+ setAccessibilityPaneTitle(getTitleForAccessibility());
+ }
+ mOriginalIcon.setForceHideDot(true);
// All views are added. Animate layout from now on.
setLayoutTransition(new LayoutTransition());
-
// Load the shortcuts on a background thread and update the container as it animates.
MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
mActivityContext, originalItemInfo, new Handler(Looper.getMainLooper()),
- this, mShortcuts, notificationKeys));
+ this, mDeepShortcuts, notificationKeys));
+ }
+
+ /**
+ * Adds any Deep Shortcuts, System Shortcuts and the Widget Shortcut to their respective
+ * containers
+ * @param deepShortcutCount number of DeepShortcutView instances
+ * @param systemShortcuts List of SystemShortcuts
+ */
+ private void addAllShortcutsMaterialU(int deepShortcutCount,
+ List<SystemShortcut> systemShortcuts) {
+
+ if (deepShortcutCount + systemShortcuts.size() <= SHORTCUT_COLLAPSE_THRESHOLD) {
+ // add all system shortcuts including widgets shortcut to same container
+ addSystemShortcutsMaterialU(systemShortcuts,
+ R.layout.system_shortcut_rows_container_material_u,
+ R.layout.system_shortcut);
+ addDeepShortcutsMaterialU(deepShortcutCount);
+ return;
+ }
+
+ List<SystemShortcut> nonWidgetSystemShortcuts =
+ getNonWidgetSystemShortcuts(systemShortcuts);
+ // If total shortcuts over threshold, collapse system shortcuts to single row
+ addSystemShortcutsMaterialU(nonWidgetSystemShortcuts,
+ R.layout.system_shortcut_icons_container_material_u,
+ R.layout.system_shortcut_icon_only);
+ // May need to recalculate row width
+ mContainerWidth = Math.max(mContainerWidth,
+ nonWidgetSystemShortcuts.size() * getResources()
+ .getDimensionPixelSize(R.dimen.system_shortcut_header_icon_touch_size));
+ // Add widget shortcut to separate container
+ Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(systemShortcuts);
+ if (widgetShortcutOpt.isPresent()) {
+ mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container_material_u,
+ this);
+ initializeWidgetShortcut(mWidgetContainer, widgetShortcutOpt.get());
+ }
+ addDeepShortcutsMaterialU(deepShortcutCount);
+ }
+
+ /**
+ * Finds the first instance of the Widgets Shortcut from the SystemShortcut List
+ * @param systemShortcuts List of SystemShortcut instances to search
+ * @return Optional Widgets SystemShortcut
+ */
+ private static Optional<SystemShortcut.Widgets> getWidgetShortcut(
+ List<SystemShortcut> systemShortcuts) {
+ return systemShortcuts
+ .stream()
+ .filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
+ .map(SystemShortcut.Widgets.class::cast)
+ .findFirst();
+ }
+
+ /**
+ * Returns list of [systemShortcuts] without the Widgets shortcut instance if found
+ * @param systemShortcuts list of SystemShortcuts to filter from
+ * @return systemShortcuts without the Widgets Shortcut
+ */
+ private static List<SystemShortcut> getNonWidgetSystemShortcuts(
+ List<SystemShortcut> systemShortcuts) {
+
+ return systemShortcuts
+ .stream()
+ .filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Inflates the given systemShortcutContainerLayout as a container, and populates with
+ * the systemShortcuts as views using the systemShortcutLayout
+ * @param systemShortcuts List of SystemShortcut to inflate as Views
+ * @param systemShortcutContainerLayout Layout Resource for the Container of shortcut Views
+ * @param systemShortcutLayout Layout Resource for the individual shortcut Views
+ */
+ private void addSystemShortcutsMaterialU(List<SystemShortcut> systemShortcuts,
+ @LayoutRes int systemShortcutContainerLayout, @LayoutRes int systemShortcutLayout) {
+
+ if (systemShortcuts.size() == 0) {
+ return;
+ }
+ mSystemShortcutContainer = inflateAndAdd(systemShortcutContainerLayout, this);
+ for (SystemShortcut shortcut : systemShortcuts) {
+ initializeSystemShortcut(systemShortcutLayout, mSystemShortcutContainer, shortcut);
+ }
+ }
+
+ /**
+ * Inflates and adds [deepShortcutCount] number of DeepShortcutView for the to a new container
+ * @param deepShortcutCount number of DeepShortcutView instances to add
+ */
+ private void addDeepShortcutsMaterialU(int deepShortcutCount) {
+ mDeepShortcutContainer = inflateAndAdd(R.layout.deep_shortcut_container, this);
+ for (int i = deepShortcutCount; i > 0; i--) {
+ DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut_material_u,
+ mDeepShortcutContainer);
+ v.getLayoutParams().width = mContainerWidth;
+ mDeepShortcuts.add(v);
+ }
+ updateHiddenShortcuts();
}
protected NotificationContainer getNotificationContainer() {
@@ -391,9 +525,9 @@
int allowedCount = mNotificationContainer != null
? MAX_SHORTCUTS_IF_NOTIFICATIONS : MAX_SHORTCUTS;
- int total = mShortcuts.size();
+ int total = mDeepShortcuts.size();
for (int i = 0; i < total; i++) {
- DeepShortcutView view = mShortcuts.get(i);
+ DeepShortcutView view = mDeepShortcuts.get(i);
view.setVisibility(i >= allowedCount ? GONE : VISIBLE);
}
}
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 80ffecc..44e3dd6 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -238,6 +238,15 @@
.collect(Collectors.toList());
}
+ /** Gets the WidgetsListContentEntry for the currently selected header. */
+ public WidgetsListContentEntry getSelectedAppWidgets(PackageUserKey packageUserKey) {
+ return (WidgetsListContentEntry) mAllWidgets.stream()
+ .filter(row -> row instanceof WidgetsListContentEntry
+ && PackageUserKey.fromPackageItemInfo(row.mPkgItem).equals(packageUserKey))
+ .findAny()
+ .orElse(null);
+ }
+
/**
* Returns a list of notifications that are relevant to given ItemInfo.
*/
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index c8455b8..2ffe34f 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -18,6 +18,7 @@
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
import android.content.Context;
@@ -203,14 +204,22 @@
systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
}
systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
-
- final PopupContainerWithArrow container =
- (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
- R.layout.popup_container, mActivity.getDragLayer(), false);
-
- container.populateAndShow((BubbleTextView) v,
- popupDataProvider.getShortcutCountForItem(item),
- Collections.emptyList(), systemShortcuts);
+ int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
+ final PopupContainerWithArrow<SecondaryDisplayLauncher> container;
+ if (ENABLE_MATERIAL_U_POPUP.get()) {
+ container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
+ R.layout.popup_container_material_u, mActivity.getDragLayer(), false);
+ container.populateAndShowRowsMaterialU((BubbleTextView) v, deepShortcutCount,
+ systemShortcuts);
+ } else {
+ container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
+ R.layout.popup_container, mActivity.getDragLayer(), false);
+ container.populateAndShow(
+ (BubbleTextView) v,
+ deepShortcutCount,
+ Collections.emptyList(),
+ systemShortcuts);
+ }
container.requestFocus();
if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 8d6a5cb..d3a237c 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -52,6 +52,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.uioverrides.flags.DeveloperOptionsFragment;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.DisplayController;
diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java
index 2390425..a01d402 100644
--- a/src/com/android/launcher3/statemanager/BaseState.java
+++ b/src/com/android/launcher3/statemanager/BaseState.java
@@ -70,4 +70,12 @@
default boolean showTaskThumbnailSplash() {
return false;
}
+
+ /**
+ * For this state, whether member variables and other forms of data state should be preserved
+ * or wiped when the state is reapplied. (See {@link StateManager#reapplyState()})
+ */
+ default boolean shouldPreserveDataStateOnReapply() {
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 34ac8c2..89d89d6 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -184,6 +184,13 @@
public void reapplyState(boolean cancelCurrentAnimation) {
boolean wasInAnimation = mConfig.currentAnimation != null;
if (cancelCurrentAnimation) {
+ // Animation canceling can trigger a cleanup routine, causing problems when we are in a
+ // launcher state that relies on member variable data. So if we are in one of those
+ // states, accelerate the current animation to its end point rather than canceling it
+ // outright.
+ if (mState.shouldPreserveDataStateOnReapply() && mConfig.currentAnimation != null) {
+ mConfig.currentAnimation.end();
+ }
mAtomicAnimationFactory.cancelAllStateElementAnimation();
cancelAnimation();
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index d31a646..0b756b6 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -208,6 +208,11 @@
);
}
+ case TestProtocol.REQUEST_WORKSPACE_CURRENT_PAGE_INDEX: {
+ return getLauncherUIProperty(Bundle::putInt,
+ launcher -> launcher.getWorkspace().getCurrentPage());
+ }
+
case TestProtocol.REQUEST_HOTSEAT_CELL_CENTER: {
final HotseatCellCenterRequest request = extra.getParcelable(
TestProtocol.TEST_INFO_REQUEST_FIELD);
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index bfd0e1b..a53751f 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -129,10 +129,7 @@
Interpolators.clampToProgress(
Interpolators.mapToProgress(EMPHASIZED_DECELERATE, 0.4f, 1f),
ALL_APPS_STATE_TRANSITION_ATOMIC, 1f);
- public static final Interpolator ALL_APPS_VERTICAL_PROGRESS_MANUAL =
- Interpolators.clampToProgress(
- Interpolators.mapToProgress(LINEAR, ALL_APPS_STATE_TRANSITION_MANUAL, 1f),
- ALL_APPS_STATE_TRANSITION_MANUAL, 1f);
+ public static final Interpolator ALL_APPS_VERTICAL_PROGRESS_MANUAL = LINEAR;
// --------
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index cf470f4..c356da9 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -448,7 +448,7 @@
@Override
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
- int splitInstructionsWidth, int threeButtonNavShift) {
+ int splitInstructionsWidth) {
out.setPivotX(0);
out.setPivotY(splitInstructionsHeight);
out.setRotation(getDegreesRotated());
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 6234462..39ef129 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -142,7 +142,7 @@
* @param splitInstructionsWidth The SplitInstructionView's width.
*/
void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
- int splitInstructionsWidth, int threeButtonNavShift);
+ int splitInstructionsWidth);
/**
* @param splitDividerSize height of split screen drag handle in portrait, width in landscape
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 75378f6..628aa9a 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -27,7 +27,6 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
-import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
@@ -51,8 +50,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
@@ -517,57 +514,29 @@
@Override
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
- int splitInstructionsWidth, int threeButtonNavShift) {
+ int splitInstructionsWidth) {
out.setPivotX(0);
out.setPivotY(splitInstructionsHeight);
out.setRotation(getDegreesRotated());
int distanceToEdge;
- if ((DisplayController.getNavigationMode(out.getContext()) == THREE_BUTTONS)
- && (dp.isTwoPanels || dp.isTablet)
- // If taskbar is in overview, overview action has dedicated space above nav buttons
- && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
- // If 3-button nav is active, align the splitInstructionsView with it.
- distanceToEdge = dp.getTaskbarOffsetY()
- + ((dp.taskbarSize - splitInstructionsHeight) / 2);
- } else {
- // If 3-button nav is not active, set bottom margin according to spec.
- if (dp.isPhone) {
- if (dp.isLandscape) {
- distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_phone_landscape);
- } else {
- distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_phone_portrait);
- }
- } else if (dp.isTwoPanels) {
- if (dp.isLandscape) {
- distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_twopanels_landscape);
- } else {
- distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_twopanels_portrait);
- }
+ if (dp.isPhone) {
+ if (dp.isLandscape) {
+ distanceToEdge = out.getResources().getDimensionPixelSize(
+ R.dimen.split_instructions_bottom_margin_phone_landscape);
} else {
- if (dp.isLandscape) {
- distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_tablet_landscape);
- } else {
- distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_tablet_portrait);
- }
+ distanceToEdge = out.getResources().getDimensionPixelSize(
+ R.dimen.split_instructions_bottom_margin_phone_portrait);
}
+ } else {
+ distanceToEdge = dp.getOverviewActionsClaimedSpaceBelow();
}
// Center the view in case of unbalanced insets on left or right of screen
int insetCorrectionX = (dp.getInsets().right - dp.getInsets().left) / 2;
// Adjust for any insets on the bottom edge
int insetCorrectionY = dp.getInsets().bottom;
- // Adjust for taskbar in overview
- int taskbarCorrectionY =
- dp.isTaskbarPresent && FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()
- ? dp.taskbarSize : 0;
- out.setTranslationX(insetCorrectionX + threeButtonNavShift);
- out.setTranslationY(-distanceToEdge + insetCorrectionY - taskbarCorrectionY);
+ out.setTranslationX(insetCorrectionX);
+ out.setTranslationY(-distanceToEdge + insetCorrectionY);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
lp.gravity = CENTER_HORIZONTAL | BOTTOM;
out.setLayoutParams(lp);
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 3363443..ec01231 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -184,7 +184,7 @@
@Override
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
- int splitInstructionsWidth, int threeButtonNavShift) {
+ int splitInstructionsWidth) {
out.setPivotX(0);
out.setPivotY(splitInstructionsHeight);
out.setRotation(getDegreesRotated());
diff --git a/src/com/android/launcher3/util/LockedUserState.kt b/src/com/android/launcher3/util/LockedUserState.kt
index 7b49583..f5e13d2 100644
--- a/src/com/android/launcher3/util/LockedUserState.kt
+++ b/src/com/android/launcher3/util/LockedUserState.kt
@@ -50,7 +50,9 @@
}
companion object {
- @VisibleForTesting val INSTANCE = MainThreadInitializedObject { LockedUserState(it) }
+ @VisibleForTesting
+ @JvmField
+ val INSTANCE = MainThreadInitializedObject { LockedUserState(it) }
@JvmStatic fun get(context: Context): LockedUserState = INSTANCE.get(context)
}
diff --git a/src/com/android/launcher3/util/ResourceHelper.kt b/src/com/android/launcher3/util/ResourceHelper.kt
new file mode 100644
index 0000000..0ca7888
--- /dev/null
+++ b/src/com/android/launcher3/util/ResourceHelper.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.util
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.content.res.XmlResourceParser
+import android.util.AttributeSet
+import kotlin.IntArray
+
+/**
+ * This class is a helper that can be subclassed in tests to provide a way to parse attributes
+ * correctly.
+ */
+open class ResourceHelper(private val context: Context, private val specsFileId: Int) {
+ open fun getXml(): XmlResourceParser {
+ return context.resources.getXml(specsFileId)
+ }
+
+ open fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray {
+ return context.obtainStyledAttributes(attrs, styleId)
+ }
+}
diff --git a/src/com/android/launcher3/util/ScrollableLayoutManager.java b/src/com/android/launcher3/util/ScrollableLayoutManager.java
index 9bc4ddc..cb6ecaa 100644
--- a/src/com/android/launcher3/util/ScrollableLayoutManager.java
+++ b/src/com/android/launcher3/util/ScrollableLayoutManager.java
@@ -20,6 +20,7 @@
import android.view.View;
import androidx.annotation.NonNull;
+import androidx.annotation.Px;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
@@ -31,6 +32,10 @@
*/
public class ScrollableLayoutManager extends GridLayoutManager {
+ public static final float PREDICTIVE_BACK_MIN_SCALE = 0.9f;
+ private static final float EXTRA_BOTTOM_SPACE_BY_HEIGHT_PERCENT =
+ (1 - PREDICTIVE_BACK_MIN_SCALE) / 2;
+
// keyed on item type
protected final SparseIntArray mCachedSizes = new SparseIntArray();
@@ -111,6 +116,13 @@
return adapter == null ? 0 : getItemsHeight(adapter, adapter.getItemCount());
}
+ @Override
+ protected void calculateExtraLayoutSpace(RecyclerView.State state, int[] extraLayoutSpace) {
+ super.calculateExtraLayoutSpace(state, extraLayoutSpace);
+ @Px int extraSpacePx = (int) (getHeight() * EXTRA_BOTTOM_SPACE_BY_HEIGHT_PERCENT);
+ extraLayoutSpace[1] = Math.max(extraLayoutSpace[1], extraSpacePx);
+ }
+
/**
* Returns the sum of the height, in pixels, of this list adapter's items from index
* 0 (inclusive) until {@code untilIndex} (exclusive). If untilIndex is same as the itemCount,
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 932bcfc..ceba0db 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -17,7 +17,6 @@
import static android.os.VibrationEffect.createPredefined;
import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
-
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -28,12 +27,17 @@
import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.os.Build;
+import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.Utilities;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.anim.PendingAnimation;
+
+import java.util.function.Consumer;
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
@@ -52,6 +56,21 @@
public static final VibrationEffect EFFECT_CLICK =
createPredefined(VibrationEffect.EFFECT_CLICK);
+ private static final float DRAG_TEXTURE_SCALE = 0.03f;
+ private static final float DRAG_COMMIT_SCALE = 0.5f;
+ private static final float DRAG_BUMP_SCALE = 0.4f;
+ private static final int DRAG_TEXTURE_EFFECT_SIZE = 200;
+
+ @Nullable
+ private final VibrationEffect mDragEffect;
+ @Nullable
+ private final VibrationEffect mCommitEffect;
+ @Nullable
+ private final VibrationEffect mBumpEffect;
+
+ private long mLastDragTime;
+ private final int mThresholdUntilNextDragCallMillis;
+
/**
* Haptic when entering overview.
*/
@@ -62,7 +81,7 @@
private boolean mIsHapticFeedbackEnabled;
- public VibratorWrapper(Context context) {
+ private VibratorWrapper(Context context) {
mVibrator = context.getSystemService(Vibrator.class);
mHasVibrator = mVibrator.hasVibrator();
if (mHasVibrator) {
@@ -75,12 +94,88 @@
}
};
resolver.registerContentObserver(Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED),
- false /* notifyForDescendents */, observer);
+ false /* notifyForDescendants */, observer);
} else {
mIsHapticFeedbackEnabled = false;
}
+
+ if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK)) {
+
+ // Drag texture, Commit, and Bump should only be used for premium phones.
+ // Before using these haptics make sure check if the device can use it
+ VibrationEffect.Composition dragEffect = VibrationEffect.startComposition();
+ for (int i = 0; i < DRAG_TEXTURE_EFFECT_SIZE; i++) {
+ dragEffect.addPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK, DRAG_TEXTURE_SCALE);
+ }
+ mDragEffect = dragEffect.compose();
+ mCommitEffect = VibrationEffect.startComposition().addPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_TICK, DRAG_COMMIT_SCALE).compose();
+ mBumpEffect = VibrationEffect.startComposition().addPrimitive(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK, DRAG_BUMP_SCALE).compose();
+ int primitiveDuration = mVibrator.getPrimitiveDurations(
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK)[0];
+
+ mThresholdUntilNextDragCallMillis =
+ DRAG_TEXTURE_EFFECT_SIZE * primitiveDuration + 100;
+ } else {
+ mDragEffect = null;
+ mCommitEffect = null;
+ mBumpEffect = null;
+ mThresholdUntilNextDragCallMillis = 0;
+ }
}
+ /**
+ * This is called when the user swipes to/from all apps. This is meant to be used in between
+ * long animation progresses so that it gives a dragging texture effect. For a better
+ * experience, this should be used in combination with vibrateForDragCommit().
+ */
+ public void vibrateForDragTexture() {
+ if (mDragEffect == null) {
+ return;
+ }
+ long currentTime = SystemClock.elapsedRealtime();
+ long elapsedTimeSinceDrag = currentTime - mLastDragTime;
+ if (elapsedTimeSinceDrag >= mThresholdUntilNextDragCallMillis) {
+ vibrate(mDragEffect);
+ mLastDragTime = currentTime;
+ }
+ }
+
+ /**
+ * This is used when user reaches the commit threshold when swiping to/from from all apps.
+ */
+ public void vibrateForDragCommit() {
+ if (mCommitEffect != null) {
+ vibrate(mCommitEffect);
+ }
+ // resetting dragTexture timestamp to be able to play dragTexture again
+ mLastDragTime = 0;
+ }
+
+ /**
+ * The bump haptic is used to be called at the end of a swipe and only if it the gesture is a
+ * FLING going to/from all apps. Client can just call this method elsewhere just for the
+ * effect.
+ */
+ public void vibrateForDragBump() {
+ if (mBumpEffect != null) {
+ vibrate(mBumpEffect);
+ }
+ }
+
+ /**
+ * This should be used to cancel a haptic in case where the haptic shouldn't be vibrating. For
+ * example, when no animation is happening but a vibrator happens to be vibrating still. Need
+ * boolean parameter for {@link PendingAnimation#addEndListener(Consumer)}.
+ */
+ public void cancelVibrate(boolean unused) {
+ UI_HELPER_EXECUTOR.execute(mVibrator::cancel);
+ // reset dragTexture timestamp to be able to play dragTexture again whenever cancelled
+ mLastDragTime = 0;
+ }
private boolean isHapticFeedbackEnabled(ContentResolver resolver) {
return Settings.System.getInt(resolver, HAPTIC_FEEDBACK_ENABLED, 0) == 1;
}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index f73347a..e2f1c04 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -17,15 +17,20 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.TABLET_BOTTOM_SHEET_SUCCESS_TRANSITION_PROGRESS;
+import static com.android.launcher3.allapps.AllAppsTransitionController.REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Property;
import android.view.MotionEvent;
@@ -33,10 +38,13 @@
import android.view.ViewGroup;
import android.view.animation.Interpolator;
+import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
+import androidx.annotation.Px;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.BaseSwipeDetector;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
@@ -85,6 +93,10 @@
protected @Nullable OnCloseListener mOnCloseBeginListener;
protected List<OnCloseListener> mOnCloseListeners = new ArrayList<>();
+ private final AnimatedFloat mSlidInViewScale = new AnimatedFloat(this::onScaleProgressChanged);
+ private boolean mIsBackProgressing;
+ @Nullable private Drawable mContentBackground;
+
public AbstractSlideInView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mActivityContext = ActivityContext.lookupContext(context);
@@ -105,6 +117,10 @@
mColorScrim = scrimColor != -1 ? createColorScrim(context, scrimColor) : null;
}
+ protected void setContentBackground(Drawable drawable) {
+ mContentBackground = drawable;
+ }
+
protected void attachToContainer() {
if (mColorScrim != null) {
getPopupContainer().addView(mColorScrim);
@@ -132,6 +148,7 @@
if (mColorScrim != null) {
mColorScrim.setAlpha(1 - mTranslationShift);
}
+ invalidate();
}
@Override
@@ -161,6 +178,68 @@
return true;
}
+ @Override
+ public void onBackProgressed(@FloatRange(from = 0.0, to = 1.0) float progress) {
+ super.onBackProgressed(progress);
+ float deceleratedProgress =
+ Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(progress);
+ mIsBackProgressing = progress > 0f;
+ mSlidInViewScale.updateValue(PREDICTIVE_BACK_MIN_SCALE
+ + (1 - PREDICTIVE_BACK_MIN_SCALE) * (1 - deceleratedProgress));
+ }
+
+ private void onScaleProgressChanged() {
+ float scaleProgress = mSlidInViewScale.value;
+ SCALE_PROPERTY.set(this, scaleProgress);
+ setClipChildren(!mIsBackProgressing);
+ mContent.setClipChildren(!mIsBackProgressing);
+ invalidate();
+ }
+
+ @Override
+ public void onBackInvoked() {
+ super.onBackInvoked();
+ animateSlideInViewToNoScale();
+ }
+
+ @Override
+ public void onBackCancelled() {
+ super.onBackCancelled();
+ animateSlideInViewToNoScale();
+ }
+
+ protected void animateSlideInViewToNoScale() {
+ mSlidInViewScale.animateToValue(1f)
+ .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
+ .start();
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ drawScaledBackground(canvas);
+ super.dispatchDraw(canvas);
+ }
+
+ /** Draw scaled background during predictive back animation. */
+ protected void drawScaledBackground(Canvas canvas) {
+ if (mContentBackground == null) {
+ return;
+ }
+ mContentBackground.setBounds(
+ mContent.getLeft(),
+ mContent.getTop() + (int) mContent.getTranslationY(),
+ mContent.getRight(),
+ mContent.getBottom() + (mIsBackProgressing ? getBottomOffsetPx() : 0));
+ mContentBackground.draw(canvas);
+ }
+
+ /** Return extra space revealed during predictive back animation. */
+ @Px
+ protected int getBottomOffsetPx() {
+ return (int) (getMeasuredHeight()
+ * (1 - PREDICTIVE_BACK_MIN_SCALE) / 2);
+ }
+
/**
* Returns {@code true} if the touch event is over the visible area of the bottom sheet.
*
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 2ab4601..b6f6223 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -199,9 +199,9 @@
}
/**
- * Returns {@code true} if popups should use color extraction.
+ * Returns {@code true} if popups can use a range of color shades instead of a singular color.
*/
- default boolean shouldUseColorExtractionForPopup() {
+ default boolean canUseMultipleShadesForPopup() {
return true;
}
@@ -313,7 +313,7 @@
*/
default boolean startActivitySafely(
View v, Intent intent, @Nullable ItemInfo item) {
-
+ Preconditions.assertUIThread();
Context context = (Context) this;
if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/launcher3/views/IconButtonView.java b/src/com/android/launcher3/views/IconButtonView.java
index 64e9327..9969eeb 100644
--- a/src/com/android/launcher3/views/IconButtonView.java
+++ b/src/com/android/launcher3/views/IconButtonView.java
@@ -31,6 +31,7 @@
import android.util.AttributeSet;
import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.icons.BaseIconFactory;
@@ -70,6 +71,15 @@
}
}
+ /** Sets given Drawable as icon */
+ public void setIconDrawable(@NonNull Drawable drawable) {
+ ColorStateList tintList = getBackgroundTintList();
+ int tint = tintList == null ? Color.WHITE : tintList.getDefaultColor();
+ try (BaseIconFactory factory = LauncherIcons.obtain(getContext())) {
+ setIcon(new IconDrawable(factory.getWhiteShadowLayer(), tint, drawable));
+ }
+ }
+
/** Updates the color of the icon's foreground layer. */
public void setForegroundTint(@ColorInt int tintColor) {
FastBitmapDrawable icon = getIcon();
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 5b57e22..315cbad 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -15,12 +15,16 @@
*/
package com.android.launcher3.views;
+import static androidx.core.content.ContextCompat.getColorStateList;
+
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -31,6 +35,7 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -139,6 +144,16 @@
mTargetRect.roundOut(outPos);
}
+ @Override
+ public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
+ if (ENABLE_MATERIAL_U_POPUP.get()) {
+ assignMarginsAndBackgrounds(viewGroup,
+ getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
+ } else {
+ assignMarginsAndBackgrounds(viewGroup, Color.TRANSPARENT);
+ }
+ }
+
public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
List<OptionItem> items, boolean shouldAddArrow) {
return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 3af2e3c..a941833 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -171,12 +171,14 @@
ta.recycle();
}
- /** @return whether there is a RecyclerView bound to this scroller. */
- public boolean hasRecyclerView() {
- return mRv != null;
+ /** Sets the popup view to show while the scroller is being dragged */
+ public void setPopupView(TextView popupView) {
+ mPopupView = popupView;
+ mPopupView.setBackground(
+ new FastScrollThumbDrawable(mThumbPaint, Utilities.isRtl(getResources())));
}
- public void setRecyclerView(FastScrollRecyclerView rv, TextView popupView) {
+ public void setRecyclerView(FastScrollRecyclerView rv) {
if (mRv != null && mOnScrollListener != null) {
mRv.removeOnScrollListener(mOnScrollListener);
}
@@ -194,10 +196,6 @@
mRv.onUpdateScrollbar(dy);
}
});
-
- mPopupView = popupView;
- mPopupView.setBackground(
- new FastScrollThumbDrawable(mThumbPaint, Utilities.isRtl(getResources())));
}
public void reattachThumbToScroll() {
@@ -283,15 +281,7 @@
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mRv.onFastScrollCompleted();
- mTouchOffsetY = 0;
- mLastTouchY = 0;
- mIgnoreDragGesture = false;
- if (mIsDragging) {
- mIsDragging = false;
- animatePopupVisibility(false);
- showActiveScrollbar(false);
- }
+ endFastScrolling();
break;
}
if (DEBUG) {
@@ -330,8 +320,21 @@
setThumbOffsetY((int) mLastTouchY);
}
+ /** End any active fast scrolling touch handling, if applicable. */
+ public void endFastScrolling() {
+ mRv.onFastScrollCompleted();
+ mTouchOffsetY = 0;
+ mLastTouchY = 0;
+ mIgnoreDragGesture = false;
+ if (mIsDragging) {
+ mIsDragging = false;
+ animatePopupVisibility(false);
+ showActiveScrollbar(false);
+ }
+ }
+
public void onDraw(Canvas canvas) {
- if (mThumbOffsetY < 0) {
+ if (mThumbOffsetY < 0 || mRv == null) {
return;
}
int saveCount = canvas.save();
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index d7235ad..bea7517 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -55,10 +55,10 @@
public class LauncherWidgetHolder {
public static final int APPWIDGET_HOST_ID = 1024;
- private static final int FLAG_LISTENING = 1;
- private static final int FLAG_STATE_IS_NORMAL = 1 << 1;
- private static final int FLAG_ACTIVITY_STARTED = 1 << 2;
- private static final int FLAG_ACTIVITY_RESUMED = 1 << 3;
+ protected static final int FLAG_LISTENING = 1;
+ protected static final int FLAG_STATE_IS_NORMAL = 1 << 1;
+ protected static final int FLAG_ACTIVITY_STARTED = 1 << 2;
+ protected static final int FLAG_ACTIVITY_RESUMED = 1 << 3;
private static final int FLAGS_SHOULD_LISTEN =
FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED | FLAG_ACTIVITY_RESUMED;
@@ -77,7 +77,7 @@
@NonNull
private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
- private int mFlags = FLAG_STATE_IS_NORMAL;
+ protected int mFlags = FLAG_STATE_IS_NORMAL;
// TODO(b/191735836): Replace with ActivityOptions.KEY_SPLASH_SCREEN_STYLE when un-hidden
private static final String KEY_SPLASH_SCREEN_STYLE = "android.activity.splashScreenStyle";
@@ -115,6 +115,13 @@
// widgets upon bind anyway. See issue 14255011 for more context.
}
+ updateDeferredView();
+ }
+
+ /**
+ * Update any views which have been deferred because the host was not listening.
+ */
+ protected void updateDeferredView() {
// We go in reverse order and inflate any deferred or cached widget
for (int i = mViews.size() - 1; i >= 0; i--) {
LauncherAppWidgetHostView view = mViews.valueAt(i);
@@ -464,7 +471,7 @@
}
final boolean listening = isListening();
- if (!listening && (mFlags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN) {
+ if (!listening && shouldListen(mFlags)) {
// Postpone starting listening until all flags are on.
startListening();
} else if (listening && (mFlags & FLAG_ACTIVITY_STARTED) == 0) {
@@ -474,6 +481,14 @@
}
/**
+ * Returns true if the holder should be listening for widget updates based
+ * on the provided state flags.
+ */
+ protected boolean shouldListen(int flags) {
+ return (flags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN;
+ }
+
+ /**
* Returns the new LauncherWidgetHolder instance
*/
public static LauncherWidgetHolder newInstance(Context context) {
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
index 9601652..3935be5 100644
--- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -17,6 +17,8 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
+import android.content.Context;
+
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
@@ -27,13 +29,28 @@
*/
public class PendingAddShortcutInfo extends PendingAddItemInfo {
- public ShortcutConfigActivityInfo activityInfo;
+ // TODO: Make it @NonNull
+ protected ShortcutConfigActivityInfo mActivityInfo;
public PendingAddShortcutInfo(ShortcutConfigActivityInfo activityInfo) {
- this.activityInfo = activityInfo;
+ this.mActivityInfo = activityInfo;
componentName = activityInfo.getComponent();
user = activityInfo.getUser();
itemType = activityInfo.getItemType();
this.container = CONTAINER_WIDGETS_TRAY;
}
+
+ public PendingAddShortcutInfo(PendingAddShortcutInfo info) {
+ super(info);
+ mActivityInfo = info.mActivityInfo;
+ }
+
+ public PendingAddShortcutInfo() { }
+
+ /**
+ * Returns the info used for creating the shortcut
+ */
+ public ShortcutConfigActivityInfo getActivityInfo(Context context) {
+ return mActivityInfo;
+ }
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index bbbc329..2dedd12 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -180,7 +180,8 @@
draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_WIDGET);
} else {
PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
- Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
+ Drawable icon = createShortcutInfo.getActivityInfo(launcher)
+ .getFullResIcon(app.getIconCache());
LauncherIcons li = LauncherIcons.obtain(launcher);
preview = new FastBitmapDrawable(
li.createScaledBitmap(icon, BaseIconFactory.MODE_DEFAULT));
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index bf521cc..4099302 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -113,6 +113,7 @@
}
mWidgetCellHorizontalPadding = getResources().getDimensionPixelSize(
R.dimen.widget_cell_horizontal_padding);
+ setContentBackground(getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet));
}
@Override
diff --git a/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java b/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java
index 7f24905..5b1da5b 100644
--- a/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java
@@ -33,9 +33,4 @@
Collections.EMPTY_LIST);
mPkgItem.title = "";
}
-
- @Override
- public int getRank() {
- return RANK_WIDGETS_TOP_SPACE;
- }
}
diff --git a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
index 1d1c9dc..0003b76 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
@@ -16,16 +16,11 @@
package com.android.launcher3.widget.model;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import androidx.annotation.IntDef;
-
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.widget.WidgetItemComparator;
-import java.lang.annotation.Retention;
import java.util.List;
import java.util.stream.Collectors;
@@ -48,38 +43,4 @@
this.mWidgets =
items.stream().sorted(new WidgetItemComparator()).collect(Collectors.toList());
}
-
- /**
- * Returns the ranking of this entry in the
- * {@link com.android.launcher3.widget.picker.WidgetsListAdapter}.
- *
- * <p>Entries with smaller value should be shown first. See
- * {@link com.android.launcher3.widget.picker.WidgetsDiffReporter} for more details.
- */
- @Rank
- public abstract int getRank();
-
- /**
- * Marker interface for subclasses that are headers for widget list items.
- *
- * @param <T> The type of this class.
- */
- public interface Header<T extends WidgetsListBaseEntry & Header<T>> {
- /** Returns whether the widget list is currently expanded. */
- boolean isWidgetListShown();
-
- /** Returns a copy of the item with the widget list shown. */
- T withWidgetListShown();
- }
-
- @Retention(SOURCE)
- @IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_SEARCH_HEADER,
- RANK_WIDGETS_LIST_CONTENT})
- public @interface Rank {
- }
-
- public static final int RANK_WIDGETS_TOP_SPACE = 1;
- public static final int RANK_WIDGETS_LIST_HEADER = 2;
- public static final int RANK_WIDGETS_LIST_SEARCH_HEADER = 3;
- public static final int RANK_WIDGETS_LIST_CONTENT = 4;
}
diff --git a/src/com/android/launcher3/widget/model/WidgetsListContentEntry.java b/src/com/android/launcher3/widget/model/WidgetsListContentEntry.java
index 73b17f1..626e0b9 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListContentEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListContentEntry.java
@@ -61,12 +61,6 @@
+ mMaxSpanSizeInCells;
}
- @Override
- @Rank
- public int getRank() {
- return RANK_WIDGETS_LIST_CONTENT;
- }
-
/**
* Returns a copy of this {@link WidgetsListContentEntry} with updated
* {@param maxSpanSizeInCells}.
diff --git a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
index 5b3ea94..68f18ae 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
@@ -15,35 +15,67 @@
*/
package com.android.launcher3.widget.model;
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.util.PluralMessageFormat;
import java.util.List;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
/** An information holder for an app which has widgets or/and shortcuts. */
-public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry
- implements WidgetsListBaseEntry.Header<WidgetsListHeaderEntry> {
+public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
- public final int widgetsCount;
- public final int shortcutsCount;
+ private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_SEARCH =
+ (context, entry) -> entry.mWidgets.stream()
+ .map(item -> item.label).sorted().collect(Collectors.joining(", "));
+
+ private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_DEFAULT =
+ (context, entry) -> {
+ List<WidgetItem> items = entry.mWidgets;
+ int wc = (int) items.stream().filter(item -> item.widgetInfo != null).count();
+ int sc = Math.max(0, items.size() - wc);
+
+ Resources resources = context.getResources();
+ if (wc == 0 && sc == 0) {
+ return null;
+ }
+
+ String subtitle;
+ if (wc > 0 && sc > 0) {
+ String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
+ R.string.widgets_count, wc);
+ String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
+ R.string.shortcuts_count, sc);
+ subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
+ widgetsCount, shortcutsCount);
+ } else if (wc > 0) {
+ subtitle = PluralMessageFormat.getIcuPluralString(context,
+ R.string.widgets_count, wc);
+ } else {
+ subtitle = PluralMessageFormat.getIcuPluralString(context,
+ R.string.shortcuts_count, sc);
+ }
+ return subtitle;
+ };
private final boolean mIsWidgetListShown;
-
- public WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items) {
- this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
- }
+ private final boolean mIsSearchEntry;
private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items, boolean isWidgetListShown) {
+ List<WidgetItem> items, boolean isSearchEntry, boolean isWidgetListShown) {
super(pkgItem, titleSectionName, items);
- widgetsCount = (int) items.stream().filter(item -> item.widgetInfo != null).count();
- shortcutsCount = Math.max(0, items.size() - widgetsCount);
+ mIsSearchEntry = isSearchEntry;
mIsWidgetListShown = isWidgetListShown;
}
/** Returns {@code true} if the widgets list associated with this header is shown. */
- @Override
public boolean isWidgetListShown() {
return mIsWidgetListShown;
}
@@ -53,10 +85,14 @@
return "Header:" + mPkgItem.packageName + ":" + mWidgets.size();
}
- @Override
- @Rank
- public int getRank() {
- return RANK_WIDGETS_LIST_HEADER;
+ public boolean isSearchEntry() {
+ return mIsSearchEntry;
+ }
+
+ @Nullable
+ public String getSubtitle(Context context) {
+ return mIsSearchEntry
+ ? SUBTITLE_SEARCH.apply(context, this) : SUBTITLE_DEFAULT.apply(context, this);
}
@Override
@@ -65,17 +101,38 @@
WidgetsListHeaderEntry otherEntry = (WidgetsListHeaderEntry) obj;
return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
&& mTitleSectionName.equals(otherEntry.mTitleSectionName)
- && mIsWidgetListShown == otherEntry.mIsWidgetListShown;
+ && mIsWidgetListShown == otherEntry.mIsWidgetListShown
+ && mIsSearchEntry == otherEntry.mIsSearchEntry;
}
/** Returns a copy of this {@link WidgetsListHeaderEntry} with the widget list shown. */
- @Override
public WidgetsListHeaderEntry withWidgetListShown() {
if (mIsWidgetListShown) return this;
return new WidgetsListHeaderEntry(
mPkgItem,
mTitleSectionName,
mWidgets,
+ mIsSearchEntry,
/* isWidgetListShown= */ true);
}
+
+ public static WidgetsListHeaderEntry create(PackageItemInfo pkgItem, String titleSectionName,
+ List<WidgetItem> items) {
+ return new WidgetsListHeaderEntry(
+ pkgItem,
+ titleSectionName,
+ items,
+ /* forSearch */ false,
+ /* isWidgetListShown= */ false);
+ }
+
+ public static WidgetsListHeaderEntry createForSearch(PackageItemInfo pkgItem,
+ String titleSectionName, List<WidgetItem> items) {
+ return new WidgetsListHeaderEntry(
+ pkgItem,
+ titleSectionName,
+ items,
+ /* forSearch */ true,
+ /* isWidgetListShown= */ false);
+ }
}
diff --git a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java
deleted file mode 100644
index 055e4ec..0000000
--- a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.model;
-
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-
-import java.util.List;
-
-/** An information holder for an app which has widgets or/and shortcuts, to be shown in search. */
-public final class WidgetsListSearchHeaderEntry extends WidgetsListBaseEntry
- implements WidgetsListBaseEntry.Header<WidgetsListSearchHeaderEntry> {
-
- private final boolean mIsWidgetListShown;
-
- public WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items) {
- this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
- }
-
- private WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items, boolean isWidgetListShown) {
- super(pkgItem, titleSectionName, items);
- mIsWidgetListShown = isWidgetListShown;
- }
-
- /** Returns {@code true} if the widgets list associated with this header is shown. */
- @Override
- public boolean isWidgetListShown() {
- return mIsWidgetListShown;
- }
-
- @Override
- public String toString() {
- return "SearchHeader:" + mPkgItem.packageName + ":" + mWidgets.size();
- }
-
- @Override
- @Rank
- public int getRank() {
- return RANK_WIDGETS_LIST_SEARCH_HEADER;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof WidgetsListSearchHeaderEntry)) return false;
- WidgetsListSearchHeaderEntry otherEntry = (WidgetsListSearchHeaderEntry) obj;
- return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
- && mTitleSectionName.equals(otherEntry.mTitleSectionName)
- && mIsWidgetListShown == otherEntry.mIsWidgetListShown;
- }
-
- /** Returns a copy of this {@link WidgetsListSearchHeaderEntry} with the widget list shown. */
- @Override
- public WidgetsListSearchHeaderEntry withWidgetListShown() {
- if (mIsWidgetListShown) return this;
- return new WidgetsListSearchHeaderEntry(
- mPkgItem,
- mTitleSectionName,
- mWidgets,
- /* isWidgetListShown= */ true);
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsDiffCallback.java b/src/com/android/launcher3/widget/picker/WidgetsDiffCallback.java
new file mode 100644
index 0000000..e610ea9
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsDiffCallback.java
@@ -0,0 +1,64 @@
+/*
+ * 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.widget.picker;
+
+import androidx.recyclerview.widget.DiffUtil.Callback;
+
+import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+
+import java.util.List;
+
+/**
+ * DiffUtil callback to compare widgets
+ */
+public class WidgetsDiffCallback extends Callback {
+
+ private final List<WidgetsListBaseEntry> mOldEntries;
+ private final List<WidgetsListBaseEntry> mNewEntries;
+
+ public WidgetsDiffCallback(
+ List<WidgetsListBaseEntry> oldEntries,
+ List<WidgetsListBaseEntry> newEntries) {
+ mOldEntries = oldEntries;
+ mNewEntries = newEntries;
+ }
+
+ @Override
+ public int getOldListSize() {
+ return mOldEntries.size();
+ }
+
+ @Override
+ public int getNewListSize() {
+ return mNewEntries.size();
+ }
+
+ @Override
+ public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+ // Items are same if they point to the same package entry
+ WidgetsListBaseEntry oldItem = mOldEntries.get(oldItemPosition);
+ WidgetsListBaseEntry newItem = mNewEntries.get(newItemPosition);
+ return oldItem.getClass().equals(newItem.getClass())
+ && oldItem.mPkgItem.equals(newItem.mPkgItem);
+ }
+
+ @Override
+ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+ // Always update all entries since the icon may have changed
+ return false;
+ }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
deleted file mode 100644
index 99374f5..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.widget.picker;
-
-import android.util.Log;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-import com.android.launcher3.widget.picker.WidgetsListAdapter.WidgetListBaseRowEntryComparator;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Do diff on widget's tray list items and call the {@link RecyclerView.Adapter}
- * methods accordingly.
- */
-public class WidgetsDiffReporter {
- private static final boolean DEBUG = false;
- private static final String TAG = "WidgetsDiffReporter";
-
- private final IconCache mIconCache;
- private final RecyclerView.Adapter mListener;
-
- public WidgetsDiffReporter(IconCache iconCache, RecyclerView.Adapter listener) {
- mIconCache = iconCache;
- mListener = listener;
- }
-
- /**
- * Notifies the difference between {@code currentEntries} & {@code newEntries} by calling the
- * relevant {@link androidx.recyclerview.widget.RecyclerView.RecyclerViewDataObserver} methods.
- */
- public void process(ArrayList<WidgetsListBaseEntry> currentEntries,
- List<WidgetsListBaseEntry> newEntries,
- WidgetListBaseRowEntryComparator comparator) {
- if (DEBUG) {
- Log.d(TAG, "process oldEntries#=" + currentEntries.size()
- + " newEntries#=" + newEntries.size());
- }
- // Early exit if either of the list is empty
- if (currentEntries.isEmpty() || newEntries.isEmpty()) {
- // Skip if both list are empty.
- // On rotation, we open the widget tray with empty. Then try to fetch the list again
- // when the animation completes (which still gives empty). And we get the final result
- // when the bind actually completes.
- if (currentEntries.size() != newEntries.size()) {
- currentEntries.clear();
- currentEntries.addAll(newEntries);
- mListener.notifyDataSetChanged();
- }
- return;
- }
- ArrayList<WidgetsListBaseEntry> orgEntries =
- (ArrayList<WidgetsListBaseEntry>) currentEntries.clone();
- Iterator<WidgetsListBaseEntry> orgIter = orgEntries.iterator();
- Iterator<WidgetsListBaseEntry> newIter = newEntries.iterator();
-
- WidgetsListBaseEntry orgRowEntry = orgIter.next();
- WidgetsListBaseEntry newRowEntry = newIter.next();
-
- do {
- int diff = compareAppNameAndType(orgRowEntry, newRowEntry, comparator);
- if (DEBUG) {
- Log.d(TAG, String.format("diff=%d orgRowEntry (%s) newRowEntry (%s)",
- diff, orgRowEntry != null ? orgRowEntry.toString() : null,
- newRowEntry != null ? newRowEntry.toString() : null));
- }
- int index = -1;
- if (diff < 0) {
- index = currentEntries.indexOf(orgRowEntry);
- mListener.notifyItemRemoved(index);
- if (DEBUG) {
- Log.d(TAG, String.format("notifyItemRemoved called (%d)%s", index,
- orgRowEntry.mTitleSectionName));
- }
- currentEntries.remove(index);
- orgRowEntry = orgIter.hasNext() ? orgIter.next() : null;
- } else if (diff > 0) {
- index = orgRowEntry != null ? currentEntries.indexOf(orgRowEntry)
- : currentEntries.size();
- currentEntries.add(index, newRowEntry);
- if (DEBUG) {
- Log.d(TAG, String.format("notifyItemInserted called (%d)%s", index,
- newRowEntry.mTitleSectionName));
- }
- newRowEntry = newIter.hasNext() ? newIter.next() : null;
- mListener.notifyItemInserted(index);
-
- } else {
- // same app name & type but,
- // did the icon, title, etc, change?
- // or did the header view changed due to user interactions?
- // or did the widget size and desc, span, etc change?
- if (!isSamePackageItemInfo(orgRowEntry.mPkgItem, newRowEntry.mPkgItem)
- || hasHeaderUpdated(orgRowEntry, newRowEntry)
- || hasWidgetsListContentChanged(orgRowEntry, newRowEntry)) {
- index = currentEntries.indexOf(orgRowEntry);
- currentEntries.set(index, newRowEntry);
- mListener.notifyItemChanged(index);
- if (DEBUG) {
- Log.d(TAG, String.format("notifyItemChanged called (%d)%s", index,
- newRowEntry.mTitleSectionName));
- }
- }
- orgRowEntry = orgIter.hasNext() ? orgIter.next() : null;
- newRowEntry = newIter.hasNext() ? newIter.next() : null;
- }
- } while(orgRowEntry != null || newRowEntry != null);
- }
-
- /**
- * Compares the app name and then entry type for the given {@link WidgetsListBaseEntry}s.
- *
- * @Return 0 if both entries' order is the same. Negative integer if {@code newRowEntry} should
- * order before {@code orgRowEntry}. Positive integer if {@code orgRowEntry} should
- * order before {@code newRowEntry}.
- */
- private int compareAppNameAndType(WidgetsListBaseEntry curRow, WidgetsListBaseEntry newRow,
- WidgetListBaseRowEntryComparator comparator) {
- if (curRow == null && newRow == null) {
- throw new IllegalStateException(
- "Cannot compare PackageItemInfo if both rows are null.");
- }
-
- if (curRow == null && newRow != null) {
- return 1; // new row needs to be inserted
- } else if (curRow != null && newRow == null) {
- return -1; // old row needs to be deleted
- }
- int diff = comparator.compare(curRow, newRow);
- if (diff == 0) {
- return newRow.getRank() - curRow.getRank();
- }
- return diff;
- }
-
- /**
- * Returns {@code true} if both {@code curRow} & {@code newRow} are
- * {@link WidgetsListContentEntry}s with a different list or arrangement of widgets.
- */
- private boolean hasWidgetsListContentChanged(WidgetsListBaseEntry curRow,
- WidgetsListBaseEntry newRow) {
- if (!(curRow instanceof WidgetsListContentEntry)
- || !(newRow instanceof WidgetsListContentEntry)) {
- return false;
- }
- return !curRow.equals(newRow);
- }
-
- /**
- * Returns {@code true} if {@code newRow} is {@link WidgetsListHeaderEntry} and its content has
- * been changed due to user interactions.
- */
- private boolean hasHeaderUpdated(WidgetsListBaseEntry curRow, WidgetsListBaseEntry newRow) {
- if (newRow instanceof WidgetsListHeaderEntry && curRow instanceof WidgetsListHeaderEntry) {
- return !curRow.equals(newRow);
- }
- if (newRow instanceof WidgetsListSearchHeaderEntry
- && curRow instanceof WidgetsListSearchHeaderEntry) {
- // Always refresh search header entries to reset rounded corners in their view holder.
- return true;
- }
- return false;
- }
-
- private boolean isSamePackageItemInfo(PackageItemInfo curInfo, PackageItemInfo newInfo) {
- return curInfo.bitmap.icon.equals(newInfo.bitmap.icon)
- && !mIconCache.isDefaultIcon(curInfo.bitmap, curInfo.user);
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index c78ecf5..77781bd 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -17,9 +17,8 @@
import static android.view.View.MeasureSpec.makeMeasureSpec;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.allapps.AllAppsTransitionController.SWIPE_ALL_APPS_TO_HOME_MIN_SCALE;
+import static com.android.launcher3.config.FeatureFlags.LARGE_SCREEN_WIDGET_PICKER;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -30,6 +29,7 @@
import android.content.pm.LauncherApps;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Process;
import android.os.UserHandle;
@@ -41,28 +41,34 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.view.WindowInsets;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.FloatRange;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.model.UserManagerState;
import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.recyclerview.ViewHolderBinder;
+import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
@@ -71,6 +77,8 @@
import com.android.launcher3.widget.BaseWidgetSheet;
import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
import com.android.launcher3.widget.util.WidgetsTableUtils;
@@ -78,6 +86,7 @@
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.IntStream;
@@ -93,6 +102,9 @@
private static final long EDUCATION_TIP_DELAY_MS = 200;
private static final long EDUCATION_DIALOG_DELAY_MS = 500;
private static final float VERTICAL_START_POSITION = 0.3f;
+ private static final int PERSONAL_TAB = 0;
+ private static final int WORK_TAB = 1;
+ private static final String SUGGESTIONS_PACKAGE_NAME = "widgets_list_suggestions_entry";
// The widget recommendation table can easily take over the entire screen on devices with small
// resolution or landscape on phone. This ratio defines the max percentage of content area that
// the table can display.
@@ -148,7 +160,7 @@
WidgetsRecyclerView searchRecyclerView =
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView;
if (mIsInSearchMode && searchRecyclerView != null) {
- searchRecyclerView.bindFastScrollbar();
+ searchRecyclerView.bindFastScrollbar(mFastScroller);
}
}
@@ -157,6 +169,18 @@
}
};
+ private final ViewOutlineProvider mViewOutlineProvider = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRect(
+ 0,
+ 0,
+ view.getMeasuredWidth(),
+ view.getMeasuredHeight() + getBottomOffsetPx()
+ );
+ }
+ };
+
private final int mTabsHeight;
private final int mWidgetSheetContentHorizontalPadding;
@@ -169,14 +193,28 @@
private StickyHeaderLayout mSearchScrollView;
private WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
+ private LinearLayout mSuggestedWidgetsContainer;
+ private WidgetsListHeader mSuggestedWidgetsHeader;
private View mTabBar;
private View mSearchBarContainer;
private WidgetsSearchBar mSearchBar;
private TextView mHeaderTitle;
+ private FrameLayout mRightPane;
+ private WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
+ private DeviceProfile mDeviceProfile;
+ private final boolean mIsTwoPane;
+
+ private int mOrientation;
private @Nullable WidgetsRecyclerView mCurrentTouchEventRecyclerView;
+ private RecyclerViewFastScroller mFastScroller;
+
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile();
+ mIsTwoPane = mDeviceProfile.isTablet
+ && mDeviceProfile.isLandscape
+ && LARGE_SCREEN_WIDGET_PICKER.get();
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
@@ -191,6 +229,7 @@
mUserManagerState.init(UserCache.INSTANCE.get(context),
context.getSystemService(UserManager.class));
+ setContentBackground(getContext().getDrawable(R.drawable.bg_widgets_full_sheet));
}
public WidgetsFullSheet(Context context, AttributeSet attrs) {
@@ -202,16 +241,31 @@
super.onFinishInflate();
mContent = findViewById(R.id.container);
+ mContent.setOutlineProvider(mViewOutlineProvider);
+ mContent.setClipToOutline(true);
+
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view
: R.layout.widgets_full_sheet_recyclerview;
+ if (mIsTwoPane) {
+ contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view_large_screen
+ : R.layout.widgets_full_sheet_recyclerview_large_screen;
+ }
layoutInflater.inflate(contentLayoutRes, mContent, true);
- RecyclerViewFastScroller fastScroller = findViewById(R.id.fast_scroller);
+ mFastScroller = findViewById(R.id.fast_scroller);
+ if (mIsTwoPane) {
+ mFastScroller.setVisibility(GONE);
+ }
+ mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
+
mAdapters.get(AdapterHolder.PRIMARY).setup(findViewById(R.id.primary_widgets_list_view));
mAdapters.get(AdapterHolder.SEARCH).setup(findViewById(R.id.search_widgets_list_view));
if (mHasWorkProfile) {
mViewPager = findViewById(R.id.widgets_view_pager);
+ mViewPager.setOutlineProvider(mViewOutlineProvider);
+ mViewPager.setClipToOutline(true);
+ mViewPager.setClipChildren(false);
mViewPager.initParentViews(this);
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.PRIMARY);
@@ -230,15 +284,60 @@
mSearchScrollView = findViewById(R.id.search_and_recommendations_container);
mSearchScrollView.setCurrentRecyclerView(findViewById(R.id.primary_widgets_list_view));
- mRecommendedWidgetsTable = mSearchScrollView.findViewById(R.id.recommended_widget_table);
+ mRecommendedWidgetsTable = mIsTwoPane
+ ? mContent.findViewById(R.id.recommended_widget_table)
+ : mSearchScrollView.findViewById(R.id.recommended_widget_table);
+
mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+ // Add suggested widgets.
+ if (mIsTwoPane) {
+ mSuggestedWidgetsContainer = mSearchScrollView.findViewById(R.id.suggestions_header);
+
+ // Inflate the suggestions header.
+ mSuggestedWidgetsHeader = (WidgetsListHeader) layoutInflater.inflate(
+ R.layout.widgets_list_row_header_two_pane,
+ mSuggestedWidgetsContainer,
+ false);
+ mSuggestedWidgetsHeader.setExpanded(true);
+
+ PackageItemInfo packageItemInfo = new PackageItemInfo(
+ /* packageName= */ SUGGESTIONS_PACKAGE_NAME,
+ Process.myUserHandle()) {
+ @Override
+ public boolean usingLowResIcon() {
+ return false;
+ }
+ };
+ packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
+ WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
+ packageItemInfo,
+ getContext().getString(R.string.suggested_widgets_header_title),
+ mActivityContext.getPopupDataProvider().getRecommendedWidgets())
+ .withWidgetListShown();
+
+ mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry);
+ mSuggestedWidgetsHeader.setIcon(
+ getContext().getDrawable(R.drawable.widget_suggestions_icon));
+ mSuggestedWidgetsHeader.setOnClickListener(view -> {
+ mSuggestedWidgetsHeader.setExpanded(true);
+ resetExpandedHeaders();
+ mRightPane.removeAllViews();
+ mRightPane.addView(mRecommendedWidgetsTable);
+ });
+ mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
+ }
+
mTabBar = mSearchScrollView.findViewById(R.id.tabs);
mSearchBarContainer = mSearchScrollView.findViewById(R.id.search_bar_container);
mSearchBar = mSearchScrollView.findViewById(R.id.widgets_search_bar);
- mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
-
+ mHeaderTitle = mIsTwoPane
+ ? mContent.findViewById(R.id.title)
+ : mSearchScrollView.findViewById(R.id.title);
+ mRightPane = mIsTwoPane ? mContent.findViewById(R.id.right_pane) : null;
+ mWidgetsListTableViewHolderBinder =
+ new WidgetsListTableViewHolderBinder(layoutInflater, this, this);
onRecommendedWidgetsBound();
onWidgetsBound();
@@ -260,6 +359,13 @@
@Override
public void onActivePageChanged(int currentActivePage) {
+
+ // if the current active page changes to personal or work we set suggestions
+ // to be the selected widget
+ if (mIsTwoPane && (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB)) {
+ mSuggestedWidgetsHeader.callOnClick();
+ }
+
AdapterHolder currentAdapterHolder = mAdapters.get(currentActivePage);
WidgetsRecyclerView currentRecyclerView =
mAdapters.get(currentActivePage).mWidgetsRecyclerView;
@@ -270,15 +376,12 @@
@Override
public void onBackProgressed(@FloatRange(from = 0.0, to = 1.0) float progress) {
- float deceleratedProgress =
- Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(progress);
- float scaleProgress = SWIPE_ALL_APPS_TO_HOME_MIN_SCALE
- + (1 - SWIPE_ALL_APPS_TO_HOME_MIN_SCALE) * (1 - deceleratedProgress);
- SCALE_PROPERTY.set(this, scaleProgress);
+ super.onBackProgressed(progress);
+ mFastScroller.setVisibility(progress > 0 ? View.INVISIBLE : View.VISIBLE);
}
private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
- recyclerView.bindFastScrollbar();
+ recyclerView.bindFastScrollbar(mFastScroller);
if (mCurrentWidgetsRecyclerView != recyclerView) {
// Only reset the scroll position & expanded apps if the currently shown recycler view
// has been updated.
@@ -292,6 +395,11 @@
private void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
// The first item is always an empty space entry. Look for any more items.
boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
+
+ if (mIsTwoPane) {
+ mRightPane.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
+ }
+
adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
@@ -428,6 +536,11 @@
View content = mHasWorkProfile
? mViewPager
: mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
+
+ if (mIsTwoPane && mRightPane != null) {
+ content = mRightPane;
+ }
+
int maxHorizontalSpans = computeMaxHorizontalSpans(content,
mWidgetSheetContentHorizontalPadding);
if (mMaxSpansPerRow != maxHorizontalSpans) {
@@ -483,7 +596,7 @@
workUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
onActivePageChanged(mViewPager.getCurrentPage());
} else {
- updateRecyclerViewVisibility(primaryUserAdapterHolder);
+ onActivePageChanged(0);
}
// Update recommended widgets section so that it occupies appropriate space on screen to
// leave enough space for presence/absence of mNoWidgetsView.
@@ -520,6 +633,9 @@
public void onSearchResults(List<WidgetsListBaseEntry> entries) {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries);
updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
+ if (mIsTwoPane) {
+ mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.selectFirstHeaderEntry();
+ }
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
}
@@ -527,6 +643,9 @@
mIsInSearchMode = isInSearchMode;
if (isInSearchMode) {
mRecommendedWidgetsTable.setVisibility(GONE);
+ if (mIsTwoPane) {
+ mSuggestedWidgetsContainer.setVisibility(GONE);
+ }
if (mHasWorkProfile) {
mViewPager.setVisibility(GONE);
mTabBar.setVisibility(GONE);
@@ -538,6 +657,10 @@
mNoWidgetsView.setVisibility(GONE);
} else {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
+ if (mIsTwoPane) {
+ mSuggestedWidgetsContainer.setVisibility(VISIBLE);
+ mSuggestedWidgetsHeader.callOnClick();
+ }
// Visibility of recommended widgets, recycler views and headers are handled in methods
// below.
onRecommendedWidgetsBound();
@@ -572,7 +695,7 @@
MeasureSpec.EXACTLY),
makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
MeasureSpec.EXACTLY));
- float maxTableHeight = (mContent.getMeasuredHeight()
+ float maxTableHeight = mIsTwoPane ? Float.MAX_VALUE : (mContent.getMeasuredHeight()
- mTabsHeight - getHeaderViewHeight()
- noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
@@ -626,7 +749,7 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- // Disable swipe down when recycler view is scrolling
+ // Disable swipe down when recycler view is scrolling or scroll view is scrolling
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = false;
WidgetsRecyclerView recyclerView = getRecyclerView();
@@ -636,6 +759,8 @@
mNoIntercept = true;
} else if (getPopupContainer().isEventOverView(recyclerView, ev)) {
mNoIntercept = !recyclerView.shouldContainerScroll(ev, getPopupContainer());
+ } else if (mIsTwoPane && getPopupContainer().isEventOverView(mRightPane, ev)) {
+ mNoIntercept = mRightPane.getScrollY() > 0;
}
if (mSearchBar.isSearchBarFocused()
@@ -649,7 +774,11 @@
/** Shows the {@link WidgetsFullSheet} on the launcher. */
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
- .inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
+ .inflate(LARGE_SCREEN_WIDGET_PICKER.get()
+ && launcher.getDeviceProfile().isTablet
+ && launcher.getDeviceProfile().isLandscape
+ ? R.layout.widgets_full_sheet_large_screen
+ : R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
sheet.attachToContainer();
sheet.mIsOpen = true;
sheet.open(animate);
@@ -746,12 +875,22 @@
if (mIsInSearchMode) {
mSearchBar.reset();
}
+
+ // Checks the orientation of the screen
+ if (LARGE_SCREEN_WIDGET_PICKER.get()
+ && mOrientation != newConfig.orientation
+ && mDeviceProfile.isTablet) {
+ mOrientation = newConfig.orientation;
+ handleClose(false);
+ show(Launcher.getLauncher(getContext()), false);
+ }
}
@Override
public void onBackInvoked() {
if (mIsInSearchMode) {
mSearchBar.reset();
+ animateSlideInViewToNoScale();
} else {
super.onBackInvoked();
}
@@ -835,16 +974,43 @@
AdapterHolder(int adapterType) {
mAdapterType = adapterType;
-
Context context = getContext();
- LauncherAppState apps = LauncherAppState.getInstance(context);
+ HeaderChangeListener headerChangeListener = new HeaderChangeListener() {
+ @Override
+ public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
+ WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
+ .getSelectedAppWidgets(selectedHeader);
+
+ if (contentEntry == null || mRightPane == null) {
+ return;
+ }
+
+ if (mSuggestedWidgetsHeader != null) {
+ mSuggestedWidgetsHeader.setExpanded(false);
+ }
+ WidgetsRowViewHolder widgetsRowViewHolder =
+ mWidgetsListTableViewHolderBinder.newViewHolder(mRightPane);
+ mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
+ contentEntry,
+ ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
+ Collections.EMPTY_LIST);
+ widgetsRowViewHolder.mDataCallback = data -> {
+ mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
+ contentEntry,
+ ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
+ Collections.singletonList(data));
+ };
+ mRightPane.removeAllViews();
+ mRightPane.addView(widgetsRowViewHolder.itemView);
+ }
+ };
mWidgetsListAdapter = new WidgetsListAdapter(
context,
LayoutInflater.from(context),
- apps.getIconCache(),
this::getEmptySpaceHeight,
/* iconClickListener= */ WidgetsFullSheet.this,
- /* iconLongClickListener= */ WidgetsFullSheet.this);
+ /* iconLongClickListener= */ WidgetsFullSheet.this,
+ mIsTwoPane ? headerChangeListener : null);
mWidgetsListAdapter.setHasStableIds(true);
switch (mAdapterType) {
case PRIMARY:
@@ -868,11 +1034,17 @@
void setup(WidgetsRecyclerView recyclerView) {
mWidgetsRecyclerView = recyclerView;
+ mWidgetsRecyclerView.setOutlineProvider(mViewOutlineProvider);
+ mWidgetsRecyclerView.setClipToOutline(true);
+ mWidgetsRecyclerView.setClipChildren(false);
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
+ mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
mWidgetsRecyclerView.setItemAnimator(mWidgetsListItemAnimator);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
- mWidgetsRecyclerView.setEdgeEffectFactory(
- ((SpringRelativeLayout) mContent).createEdgeEffectFactory());
+ if (!mIsTwoPane) {
+ mWidgetsRecyclerView.setEdgeEffectFactory(
+ ((SpringRelativeLayout) mContent).createEdgeEffectFactory());
+ }
// Recycler view binds to fast scroller when it is attached to screen. Make sure
// search recycler view is bound to fast scroller if user is in search mode at the time
// of attachment.
@@ -882,4 +1054,15 @@
mWidgetsListAdapter.setMaxHorizontalSpansPerRow(mMaxSpansPerRow);
}
}
+
+ /**
+ * This is a listener for when the selected header gets changed in the left pane.
+ */
+ public interface HeaderChangeListener {
+ /**
+ * Sets the right pane to have the widgets for the currently selected header from
+ * the left pane.
+ */
+ void onHeaderChanged(@NonNull PackageUserKey selectedHeader);
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index e6b9dca..c28402e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -32,13 +32,14 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.DiffUtil.DiffResult;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.launcher3.R;
-import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.recyclerview.ViewHolderBinder;
import com.android.launcher3.util.LabelComparator;
@@ -48,7 +49,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
import java.util.Arrays;
@@ -81,13 +81,12 @@
public static final int VIEW_TYPE_WIDGETS_SPACE = R.id.view_type_widgets_space;
public static final int VIEW_TYPE_WIDGETS_LIST = R.id.view_type_widgets_list;
public static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
- public static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
private final Context mContext;
- private final WidgetsDiffReporter mDiffReporter;
private final SparseArray<ViewHolderBinder> mViewHolderBinders = new SparseArray<>();
private final WidgetListBaseRowEntryComparator mRowComparator =
new WidgetListBaseRowEntryComparator();
+ @Nullable private final WidgetsFullSheet.HeaderChangeListener mHeaderChangeListener;
private final List<WidgetsListBaseEntry> mAllEntries = new ArrayList<>();
private ArrayList<WidgetsListBaseEntry> mVisibleEntries = new ArrayList<>();
@@ -95,7 +94,6 @@
private Predicate<WidgetsListBaseEntry> mHeaderAndSelectedContentFilter = entry ->
entry instanceof WidgetsListHeaderEntry
- || entry instanceof WidgetsListSearchHeaderEntry
|| PackageUserKey.fromPackageItemInfo(entry.mPkgItem)
.equals(mWidgetsContentVisiblePackageUserKey);
@Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
@@ -104,29 +102,21 @@
private int mMaxSpanSize = 4;
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
- IconCache iconCache, IntSupplier emptySpaceHeightProvider,
- OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
+ IntSupplier emptySpaceHeightProvider, OnClickListener iconClickListener,
+ OnLongClickListener iconLongClickListener,
+ WidgetsFullSheet.HeaderChangeListener headerChangeListener) {
+ mHeaderChangeListener = headerChangeListener;
mContext = context;
- mDiffReporter = new WidgetsDiffReporter(iconCache, this);
- WidgetsListDrawableFactory listDrawableFactory = new WidgetsListDrawableFactory(context);
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_LIST,
new WidgetsListTableViewHolderBinder(
- layoutInflater, iconClickListener, iconLongClickListener,
- listDrawableFactory));
+ layoutInflater, iconClickListener, iconLongClickListener));
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_HEADER,
new WidgetsListHeaderViewHolderBinder(
- layoutInflater,
- /* onHeaderClickListener= */ this,
- listDrawableFactory));
- mViewHolderBinders.put(
- VIEW_TYPE_WIDGETS_SEARCH_HEADER,
- new WidgetsListSearchHeaderViewHolderBinder(
- layoutInflater,
- /* onHeaderClickListener= */ this,
- listDrawableFactory));
+ layoutInflater, /* onHeaderClickListener= */ this,
+ headerChangeListener != null));
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_SPACE,
new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
@@ -196,14 +186,16 @@
getOffsetForPosition(previousPositionForPackageUserKey);
List<WidgetsListBaseEntry> newVisibleEntries = mAllEntries.stream()
- .filter(entry -> ((mFilter == null || mFilter.test(entry))
+ .filter(entry -> (((mFilter == null || mFilter.test(entry))
&& mHeaderAndSelectedContentFilter.test(entry))
|| entry instanceof WidgetListSpaceEntry)
+ && (mHeaderChangeListener == null
+ || !(entry instanceof WidgetsListContentEntry)))
.map(entry -> {
- if (entry instanceof WidgetsListBaseEntry.Header<?>
+ if (entry instanceof WidgetsListHeaderEntry
&& matchesKey(entry, mWidgetsContentVisiblePackageUserKey)) {
// Adjust the original entries to expand headers for the selected content.
- return ((WidgetsListBaseEntry.Header<?>) entry).withWidgetListShown();
+ return ((WidgetsListHeaderEntry) entry).withWidgetListShown();
} else if (entry instanceof WidgetsListContentEntry) {
// Adjust the original content entries to accommodate for the current
// maxSpanSize.
@@ -213,7 +205,11 @@
})
.collect(Collectors.toList());
- mDiffReporter.process(mVisibleEntries, newVisibleEntries, mRowComparator);
+ DiffResult diffResult = DiffUtil.calculateDiff(
+ new WidgetsDiffCallback(mVisibleEntries, newVisibleEntries), false);
+ mVisibleEntries.clear();
+ mVisibleEntries.addAll(newVisibleEntries);
+ diffResult.dispatchUpdatesTo(this);
if (mPendingClickHeader != null) {
// Get the position for the clicked header after adjusting the visible entries. The
@@ -225,11 +221,10 @@
}
}
-
/** Returns whether {@code entry} matches {@code key}. */
private static boolean isHeaderForPackageUserKey(
@NonNull WidgetsListBaseEntry entry, @Nullable PackageUserKey key) {
- return entry instanceof WidgetsListBaseEntry.Header && matchesKey(entry, key);
+ return entry instanceof WidgetsListHeaderEntry && matchesKey(entry, key);
}
private static boolean matchesKey(@NonNull WidgetsListBaseEntry entry,
@@ -258,7 +253,6 @@
@Override
public void onBindViewHolder(ViewHolder holder, int pos, List<Object> payloads) {
ViewHolderBinder viewHolderBinder = mViewHolderBinders.get(getItemViewType(pos));
- WidgetsListBaseEntry entry = mVisibleEntries.get(pos);
// The first entry has an empty space, count from second entries.
int listPos = (pos > 1) ? POSITION_DEFAULT : POSITION_FIRST;
@@ -268,6 +262,18 @@
viewHolderBinder.bindViewHolder(holder, mVisibleEntries.get(pos), listPos, payloads);
}
+ /**
+ * Selects the first visible header. This is used in search as we want to always select the
+ * first header in the new list that gets generated as we search.
+ */
+ void selectFirstHeaderEntry() {
+ mVisibleEntries.stream()
+ .filter(entry -> entry instanceof WidgetsListHeaderEntry)
+ .findFirst()
+ .ifPresent(entry ->
+ onHeaderClicked(true, PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
+ }
+
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (DEBUG) {
@@ -305,8 +311,6 @@
return VIEW_TYPE_WIDGETS_LIST;
} else if (entry instanceof WidgetsListHeaderEntry) {
return VIEW_TYPE_WIDGETS_HEADER;
- } else if (entry instanceof WidgetsListSearchHeaderEntry) {
- return VIEW_TYPE_WIDGETS_SEARCH_HEADER;
} else if (entry instanceof WidgetListSpaceEntry) {
return VIEW_TYPE_WIDGETS_SPACE;
}
@@ -318,6 +322,9 @@
// Ignore invalid clicks, such as collapsing a package that isn't currently expanded.
if (!showWidgets && !packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) return;
+ if (mHeaderChangeListener != null
+ && packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) return;
+
if (showWidgets) {
mWidgetsContentVisiblePackageUserKey = packageUserKey;
ActivityContext.lookupContext(mContext)
@@ -331,6 +338,10 @@
mPendingClickHeader = packageUserKey;
updateVisibleEntries();
+
+ if (mHeaderChangeListener != null && mWidgetsContentVisiblePackageUserKey != null) {
+ mHeaderChangeListener.onHeaderChanged(mWidgetsContentVisiblePackageUserKey);
+ }
}
/**
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java b/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java
deleted file mode 100644
index 984a274..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListDrawableFactory.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.picker;
-
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.FIRST;
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.FIRST_EXPANDED;
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.LAST;
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE;
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE_EXPANDED;
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.SINGLE;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.RippleDrawable;
-import android.graphics.drawable.StateListDrawable;
-
-import com.android.launcher3.R;
-import com.android.launcher3.util.Themes;
-
-/** Factory for creating drawables to use as background for list elements. */
-final class WidgetsListDrawableFactory {
-
- private final float mTopBottomCornerRadius;
- private final float mMiddleCornerRadius;
- private final ColorStateList mSurfaceColor;
- private final ColorStateList mRippleColor;
- private final int mVerticalPadding;
- private final int mHeaderMargin;
-
- WidgetsListDrawableFactory(Context context) {
- Resources res = context.getResources();
- mTopBottomCornerRadius = res.getDimension(R.dimen.widget_list_top_bottom_corner_radius);
- mMiddleCornerRadius = res.getDimension(R.dimen.widget_list_content_corner_radius);
- mSurfaceColor = context.getColorStateList(R.color.surface);
- mRippleColor = ColorStateList.valueOf(
- Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
- mVerticalPadding =
- res.getDimensionPixelSize(R.dimen.widget_list_header_view_vertical_padding);
- mHeaderMargin = res.getDimensionPixelSize(R.dimen.widget_list_entry_spacing);
- }
-
- /**
- * Creates a drawable for widget header list items. This drawable supports all positions
- * in {@link WidgetsListDrawableState}.
- */
- Drawable createHeaderBackgroundDrawable() {
- StateListDrawable stateList = new StateListDrawable();
- stateList.addState(
- SINGLE.mStateSet,
- createRoundedRectDrawable(mTopBottomCornerRadius, mTopBottomCornerRadius));
- stateList.addState(
- FIRST_EXPANDED.mStateSet,
- createRoundedRectDrawable(mTopBottomCornerRadius, 0));
- stateList.addState(
- FIRST.mStateSet,
- createRoundedRectDrawable(mTopBottomCornerRadius, mMiddleCornerRadius));
- stateList.addState(
- MIDDLE_EXPANDED.mStateSet,
- createRoundedRectDrawable(mMiddleCornerRadius, 0));
- stateList.addState(
- MIDDLE.mStateSet,
- createRoundedRectDrawable(mMiddleCornerRadius, mMiddleCornerRadius));
- stateList.addState(
- LAST.mStateSet,
- createRoundedRectDrawable(mMiddleCornerRadius, mTopBottomCornerRadius));
- RippleDrawable ripple =
- new RippleDrawable(mRippleColor, /* content= */ stateList, /* mask= */ stateList);
- ripple.setPadding(0, mVerticalPadding, 0, mVerticalPadding);
- return new InsetDrawable(ripple, 0, mHeaderMargin, 0, 0);
- }
-
- /**
- * Creates a drawable for widget content list items. This state list supports the middle and
- * last states.
- */
- Drawable createContentBackgroundDrawable() {
- StateListDrawable stateList = new StateListDrawable();
- stateList.addState(
- MIDDLE.mStateSet,
- createRoundedRectDrawable(0, mMiddleCornerRadius));
- stateList.addState(
- LAST.mStateSet,
- createRoundedRectDrawable(0, mTopBottomCornerRadius));
- return new RippleDrawable(mRippleColor, /* content= */ stateList, /* mask= */ stateList);
- }
-
- /** Creates a rounded-rect drawable with the specified radii. */
- private Drawable createRoundedRectDrawable(float topRadius, float bottomRadius) {
- GradientDrawable backgroundMask = new GradientDrawable();
- backgroundMask.setColor(mSurfaceColor);
- backgroundMask.setShape(GradientDrawable.RECTANGLE);
- backgroundMask.setCornerRadii(
- new float[]{
- topRadius,
- topRadius,
- topRadius,
- topRadius,
- bottomRadius,
- bottomRadius,
- bottomRadius,
- bottomRadius
- });
- return backgroundMask;
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListDrawableState.java b/src/com/android/launcher3/widget/picker/WidgetsListDrawableState.java
index 94f292b..ca69ffe 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListDrawableState.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListDrawableState.java
@@ -21,9 +21,7 @@
*/
enum WidgetsListDrawableState {
FIRST(new int[]{android.R.attr.state_first}),
- FIRST_EXPANDED(new int[]{android.R.attr.state_first, android.R.attr.state_expanded}),
MIDDLE(new int[]{android.R.attr.state_middle}),
- MIDDLE_EXPANDED(new int[]{android.R.attr.state_middle, android.R.attr.state_expanded}),
LAST(new int[]{android.R.attr.state_last}),
SINGLE(new int[]{android.R.attr.state_single});
@@ -33,12 +31,10 @@
mStateSet = stateSet;
}
- static WidgetsListDrawableState obtain(boolean isFirst, boolean isLast, boolean isExpanded) {
+ static WidgetsListDrawableState obtain(boolean isFirst, boolean isLast) {
if (isFirst && isLast) return SINGLE;
- if (isFirst && isExpanded) return FIRST_EXPANDED;
if (isFirst) return FIRST;
if (isLast) return LAST;
- if (isExpanded) return MIDDLE_EXPANDED;
return MIDDLE;
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 48df04f..b5e7401 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -15,16 +15,14 @@
*/
package com.android.launcher3.widget.picker;
-
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -40,12 +38,8 @@
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.PluralMessageFormat;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.stream.Collectors;
/**
* A UI represents a header of an app shown in the full widgets tray.
@@ -55,19 +49,18 @@
*/
public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpdateReceiver {
- private boolean mEnableIconUpdateAnimation = false;
+ private static final int[] EXPANDED_DRAWABLE_STATE = new int[] {android.R.attr.state_expanded};
+
+ private final int mIconSize;
@Nullable private HandlerRunnable mIconLoadRequest;
@Nullable private Drawable mIconDrawable;
- private final int mIconSize;
-
+ @Nullable private WidgetsListDrawableState mListDrawableState;
private ImageView mAppIcon;
private TextView mTitle;
private TextView mSubtitle;
-
- private CheckBox mExpandToggle;
+ private boolean mEnableIconUpdateAnimation = false;
private boolean mIsExpanded = false;
- @Nullable private WidgetsListDrawableState mListDrawableState;
public WidgetsListHeader(Context context) {
this(context, /* attrs= */ null);
@@ -94,7 +87,6 @@
mAppIcon = findViewById(R.id.app_icon);
mTitle = findViewById(R.id.app_title);
mSubtitle = findViewById(R.id.app_subtitle);
- mExpandToggle = findViewById(R.id.toggle);
setAccessibilityDelegate(new AccessibilityDelegate() {
@Override
@@ -123,27 +115,16 @@
});
}
- /**
- * Sets a {@link OnExpansionChangeListener} to get a callback when this app widgets section
- * expands / collapses.
- */
- @UiThread
- public void setOnExpandChangeListener(
- @Nullable OnExpansionChangeListener onExpandChangeListener) {
- // Use the entire touch area of this view to expand / collapse an app widgets section.
- setOnClickListener(view -> {
- setExpanded(!mIsExpanded);
- if (onExpandChangeListener != null) {
- onExpandChangeListener.onExpansionChange(mIsExpanded);
- }
- });
- }
-
/** Sets the expand toggle to expand / collapse. */
@UiThread
public void setExpanded(boolean isExpanded) {
this.mIsExpanded = isExpanded;
- mExpandToggle.setChecked(isExpanded);
+ refreshDrawableState();
+ }
+
+ /** @return true if this header is expanded. */
+ public boolean isExpanded() {
+ return mIsExpanded;
}
/** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */
@@ -157,13 +138,8 @@
/** Apply app icon, labels and tag using a generic {@link WidgetsListHeaderEntry}. */
@UiThread
public void applyFromItemInfoWithIcon(WidgetsListHeaderEntry entry) {
- applyIconAndLabel(entry);
- }
-
- @UiThread
- private void applyIconAndLabel(WidgetsListHeaderEntry entry) {
PackageItemInfo info = entry.mPkgItem;
- setIcon(info);
+ setIcon(info.newIcon(getContext()));
setTitles(entry);
setExpanded(entry.isWidgetListShown());
@@ -172,9 +148,7 @@
verifyHighRes();
}
- private void setIcon(PackageItemInfo info) {
- Drawable icon;
- icon = info.newIcon(getContext());
+ void setIcon(Drawable icon) {
applyDrawables(icon);
mIconDrawable = icon;
if (mIconDrawable != null) {
@@ -205,55 +179,13 @@
private void setTitles(WidgetsListHeaderEntry entry) {
mTitle.setText(entry.mPkgItem.title);
- Resources resources = getContext().getResources();
- if (entry.widgetsCount == 0 && entry.shortcutsCount == 0) {
+ String subtitle = entry.getSubtitle(getContext());
+ if (TextUtils.isEmpty(subtitle)) {
mSubtitle.setVisibility(GONE);
- return;
- }
-
- String subtitle;
- if (entry.widgetsCount > 0 && entry.shortcutsCount > 0) {
- String widgetsCount = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.widgets_count, entry.widgetsCount);
- String shortcutsCount = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.shortcuts_count, entry.shortcutsCount);
- subtitle = resources.getString(R.string.widgets_and_shortcuts_count, widgetsCount,
- shortcutsCount);
- } else if (entry.widgetsCount > 0) {
- subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.widgets_count, entry.widgetsCount);
} else {
- subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.shortcuts_count, entry.shortcutsCount);
+ mSubtitle.setText(subtitle);
+ mSubtitle.setVisibility(VISIBLE);
}
- mSubtitle.setText(subtitle);
- mSubtitle.setVisibility(VISIBLE);
- }
-
- /** Apply app icon, labels and tag using a generic {@link WidgetsListSearchHeaderEntry}. */
- @UiThread
- public void applyFromItemInfoWithIcon(WidgetsListSearchHeaderEntry entry) {
- applyIconAndLabel(entry);
- }
-
- @UiThread
- private void applyIconAndLabel(WidgetsListSearchHeaderEntry entry) {
- PackageItemInfo info = entry.mPkgItem;
- setIcon(info);
- setTitles(entry);
- setExpanded(entry.isWidgetListShown());
-
- super.setTag(info);
-
- verifyHighRes();
- }
-
- private void setTitles(WidgetsListSearchHeaderEntry entry) {
- mTitle.setText(entry.mPkgItem.title);
-
- mSubtitle.setText(entry.mWidgets.stream()
- .map(item -> item.label).sorted().collect(Collectors.joining(", ")));
- mSubtitle.setVisibility(VISIBLE);
}
@Override
@@ -265,7 +197,7 @@
// Optimization: Starting in N, pre-uploads the bitmap to RenderThread.
info.bitmap.icon.prepareToDraw();
- setIcon((PackageItemInfo) info);
+ setIcon(info.newIcon(getContext()));
mEnableIconUpdateAnimation = false;
}
@@ -273,12 +205,15 @@
@Override
protected int[] onCreateDrawableState(int extraSpace) {
- if (mListDrawableState == null) return super.onCreateDrawableState(extraSpace);
- // Augment the state set from the super implementation with the custom states from
- // mListDrawableState.
- int[] drawableState =
- super.onCreateDrawableState(extraSpace + mListDrawableState.mStateSet.length);
- mergeDrawableStates(drawableState, mListDrawableState.mStateSet);
+ // We create a drawable state with an additional two spaces to be able to fit expanded state
+ // and the list drawable state.
+ int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
+ if (mIsExpanded) {
+ mergeDrawableStates(drawableState, EXPANDED_DRAWABLE_STATE);
+ }
+ if (mListDrawableState != null) {
+ mergeDrawableStates(drawableState, mListDrawableState.mStateSet);
+ }
return drawableState;
}
@@ -296,10 +231,4 @@
}
}
}
-
- /** A listener for the widget section expansion / collapse events. */
- public interface OnExpansionChangeListener {
- /** Notifies that the widget section is expanded or collapsed. */
- void onExpansionChange(boolean isExpanded);
- }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
index c6a7285..af4a5e6 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
@@ -32,22 +32,23 @@
ViewHolderBinder<WidgetsListHeaderEntry, WidgetsListHeaderHolder> {
private final LayoutInflater mLayoutInflater;
private final OnHeaderClickListener mOnHeaderClickListener;
- private final WidgetsListDrawableFactory mListDrawableFactory;
+ private final boolean mIsTwoPane;
public WidgetsListHeaderViewHolderBinder(LayoutInflater layoutInflater,
- OnHeaderClickListener onHeaderClickListener,
- WidgetsListDrawableFactory listDrawableFactory) {
+ OnHeaderClickListener onHeaderClickListener, boolean isTwoPane) {
mLayoutInflater = layoutInflater;
mOnHeaderClickListener = onHeaderClickListener;
- mListDrawableFactory = listDrawableFactory;
+ mIsTwoPane = isTwoPane;
}
@Override
public WidgetsListHeaderHolder newViewHolder(ViewGroup parent) {
- WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
- R.layout.widgets_list_row_header, parent, false);
- header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
- return new WidgetsListHeaderHolder(header);
+ return new WidgetsListHeaderHolder((WidgetsListHeader) mLayoutInflater.inflate(
+ mIsTwoPane
+ ? R.layout.widgets_list_row_header_two_pane
+ : R.layout.widgets_list_row_header,
+ parent,
+ false));
}
@Override
@@ -59,10 +60,11 @@
widgetsListHeader.setListDrawableState(
WidgetsListDrawableState.obtain(
(position & POSITION_FIRST) != 0,
- (position & POSITION_LAST) != 0,
- /* isExpanded= */ data.isWidgetListShown()));
- widgetsListHeader.setOnExpandChangeListener(isExpanded ->
- mOnHeaderClickListener.onHeaderClicked(isExpanded,
- PackageUserKey.fromPackageItemInfo(data.mPkgItem)));
+ (position & POSITION_LAST) != 0));
+ widgetsListHeader.setOnClickListener(view -> {
+ widgetsListHeader.setExpanded(mIsTwoPane || !widgetsListHeader.isExpanded());
+ mOnHeaderClickListener.onHeaderClicked(widgetsListHeader.isExpanded(),
+ PackageUserKey.fromPackageItemInfo(data.mPkgItem));
+ });
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderHolder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderHolder.java
deleted file mode 100644
index 9562af3..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderHolder.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.picker;
-
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-
-/**
- * A {@link ViewHolder} for {@link WidgetsListHeader} of an app, which renders the app icon, the app
- * name, label and a button for showing / hiding widgets.
- */
-public final class WidgetsListSearchHeaderHolder extends ViewHolder {
- final WidgetsListHeader mWidgetsListHeader;
-
- public WidgetsListSearchHeaderHolder(WidgetsListHeader view) {
- super(view);
-
- mWidgetsListHeader = view;
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
deleted file mode 100644
index 2b27fc2..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.picker;
-
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.android.launcher3.R;
-import com.android.launcher3.recyclerview.ViewHolderBinder;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.List;
-
-/**
- * Binds data from {@link WidgetsListHeaderEntry} to UI elements in {@link WidgetsListHeaderHolder}.
- */
-public final class WidgetsListSearchHeaderViewHolderBinder implements
- ViewHolderBinder<WidgetsListSearchHeaderEntry, WidgetsListSearchHeaderHolder> {
- private final LayoutInflater mLayoutInflater;
- private final OnHeaderClickListener mOnHeaderClickListener;
- private final WidgetsListDrawableFactory mListDrawableFactory;
-
- public WidgetsListSearchHeaderViewHolderBinder(LayoutInflater layoutInflater,
- OnHeaderClickListener onHeaderClickListener,
- WidgetsListDrawableFactory listDrawableFactory) {
- mLayoutInflater = layoutInflater;
- mOnHeaderClickListener = onHeaderClickListener;
- mListDrawableFactory = listDrawableFactory;
- }
-
- @Override
- public WidgetsListSearchHeaderHolder newViewHolder(ViewGroup parent) {
- WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
- R.layout.widgets_list_row_header, parent, false);
- header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
- return new WidgetsListSearchHeaderHolder(header);
- }
-
- @Override
- public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
- WidgetsListSearchHeaderEntry data, @ListPosition int position, List<Object> payloads) {
- WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- widgetsListHeader.applyFromItemInfoWithIcon(data);
- widgetsListHeader.setExpanded(data.isWidgetListShown());
- widgetsListHeader.setListDrawableState(
- WidgetsListDrawableState.obtain(
- (position & POSITION_FIRST) != 0,
- (position & POSITION_LAST) != 0,
- /* isExpanded= */ data.isWidgetListShown()));
- widgetsListHeader.setOnExpandChangeListener(isExpanded ->
- mOnHeaderClickListener.onHeaderClicked(isExpanded,
- PackageUserKey.fromPackageItemInfo(data.mPkgItem)));
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 05e26ad..2e8f0ab 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.widget.picker;
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.LAST;
-import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE;
-
import android.graphics.Bitmap;
import android.util.Log;
import android.util.Pair;
@@ -51,17 +48,14 @@
private final LayoutInflater mLayoutInflater;
private final OnClickListener mIconClickListener;
private final OnLongClickListener mIconLongClickListener;
- private final WidgetsListDrawableFactory mListDrawableFactory;
public WidgetsListTableViewHolderBinder(
LayoutInflater layoutInflater,
OnClickListener iconClickListener,
- OnLongClickListener iconLongClickListener,
- WidgetsListDrawableFactory listDrawableFactory) {
+ OnLongClickListener iconLongClickListener) {
mLayoutInflater = layoutInflater;
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
- mListDrawableFactory = listDrawableFactory;
}
@Override
@@ -70,12 +64,8 @@
Log.v(TAG, "\nonCreateViewHolder");
}
- WidgetsRowViewHolder viewHolder =
- new WidgetsRowViewHolder(mLayoutInflater.inflate(
+ return new WidgetsRowViewHolder(mLayoutInflater.inflate(
R.layout.widgets_table_container, parent, false));
- viewHolder.tableContainer.setBackgroundDrawable(
- mListDrawableFactory.createContentBackgroundDrawable());
- return viewHolder;
}
@Override
@@ -91,7 +81,11 @@
Log.d(TAG, String.format("onBindViewHolder [widget#=%d, table.getChildCount=%d]",
entry.mWidgets.size(), table.getChildCount()));
}
- table.setListDrawableState(((position & POSITION_LAST) != 0) ? LAST : MIDDLE);
+ table.setListDrawableState(
+ WidgetsListDrawableState.obtain(
+ (position & POSITION_FIRST) != 0,
+ (position & POSITION_LAST) != 0));
+
List<ArrayList<WidgetItem>> widgetItemsTable =
WidgetsTableUtils.groupWidgetItemsIntoTableWithReordering(
entry.mWidgets, entry.getMaxSpanSizeInCells());
@@ -110,13 +104,8 @@
// When preview loads, notify adapter to rebind the item and possibly animate
widget.applyFromCellItem(widgetItem, 1f,
- bitmap -> {
- if (holder.getBindingAdapter() != null) {
- holder.getBindingAdapter().notifyItemChanged(
- holder.getBindingAdapterPosition(),
- Pair.create(widgetItem, bitmap));
- }
- }, holder.previewCache.get(widgetItem));
+ bitmap -> holder.onPreviewLoaded(Pair.create(widgetItem, bitmap)),
+ holder.previewCache.get(widgetItem));
}
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
index fe2d84b..7411459 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget.picker;
import android.graphics.Bitmap;
+import android.util.Pair;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
@@ -25,16 +26,33 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Consumer;
/** A {@link ViewHolder} for showing widgets of an app in the full widget picker. */
public final class WidgetsRowViewHolder extends ViewHolder {
public final WidgetsListTableView tableContainer;
public final Map<WidgetItem, Bitmap> previewCache = new HashMap<>();
+ Consumer<Pair<WidgetItem, Bitmap>> mDataCallback;
public WidgetsRowViewHolder(View v) {
super(v);
tableContainer = v.findViewById(R.id.widgets_table);
}
+
+ /**
+ * When the preview is loaded we callback to notify that the preview loaded and we rebind the
+ * view.
+ *
+ * @param data is the payload which is needed when binding the view.
+ */
+ public void onPreviewLoaded(Pair<WidgetItem, Bitmap> data) {
+ if (mDataCallback != null) {
+ mDataCallback.accept(data);
+ }
+ if (getBindingAdapter() != null) {
+ getBindingAdapter().notifyItemChanged(getBindingAdapterPosition(), data);
+ }
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
index 9be3b5f..613066a 100644
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
+++ b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
@@ -28,7 +28,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
import java.util.List;
@@ -72,7 +71,7 @@
List<WidgetItem> matchedWidgetItems = filterWidgetItems(
input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
if (matchedWidgetItems.size() > 0) {
- results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
+ results.add(WidgetsListHeaderEntry.createForSearch(headerEntry.mPkgItem,
headerEntry.mTitleSectionName, matchedWidgetItems));
results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
headerEntry.mTitleSectionName, matchedWidgetItems));
diff --git a/src/com/android/launcher3/widget/util/WidgetSizes.java b/src/com/android/launcher3/widget/util/WidgetSizes.java
index fb2d63b..601c1b5 100644
--- a/src/com/android/launcher3/widget/util/WidgetSizes.java
+++ b/src/com/android/launcher3/widget/util/WidgetSizes.java
@@ -24,6 +24,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
+import android.util.Log;
import android.util.Size;
import android.util.SizeF;
@@ -162,6 +163,8 @@
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, rect.right);
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, rect.bottom);
options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, paddedSizes);
+ Log.d("b/267448330", "provider: " + provider + ", paddedSizes: " + paddedSizes
+ + ", getMinMaxSizes: " + rect);
return options;
}
diff --git a/src/com/android/launcher3/workspace/WorkspaceSpecs.kt b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
new file mode 100644
index 0000000..971fd9b
--- /dev/null
+++ b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
@@ -0,0 +1,251 @@
+/*
+ * 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.workspace
+
+import android.content.res.TypedArray
+import android.content.res.XmlResourceParser
+import android.util.AttributeSet
+import android.util.Log
+import android.util.TypedValue
+import android.util.Xml
+import com.android.launcher3.R
+import com.android.launcher3.util.ResourceHelper
+import java.io.IOException
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParserException
+
+private const val TAG = "WorkspaceSpecs"
+
+class WorkspaceSpecs(resourceHelper: ResourceHelper) {
+ object XmlTags {
+ const val WORKSPACE_SPECS = "workspaceSpecs"
+
+ const val WORKSPACE_SPEC = "workspaceSpec"
+ const val START_PADDING = "startPadding"
+ const val END_PADDING = "endPadding"
+ const val GUTTER = "gutter"
+ const val CELL_SIZE = "cellSize"
+ }
+
+ val workspaceHeightSpecList = mutableListOf<WorkspaceSpec>()
+ val workspaceWidthSpecList = mutableListOf<WorkspaceSpec>()
+
+ init {
+ try {
+ val parser: XmlResourceParser = resourceHelper.getXml()
+ val depth = parser.depth
+ var type: Int
+ while (
+ (parser.next().also { type = it } != XmlPullParser.END_TAG ||
+ parser.depth > depth) && type != XmlPullParser.END_DOCUMENT
+ ) {
+ if (type == XmlPullParser.START_TAG && XmlTags.WORKSPACE_SPECS == parser.name) {
+ val displayDepth = parser.depth
+ while (
+ (parser.next().also { type = it } != XmlPullParser.END_TAG ||
+ parser.depth > displayDepth) && type != XmlPullParser.END_DOCUMENT
+ ) {
+ if (
+ type == XmlPullParser.START_TAG && XmlTags.WORKSPACE_SPEC == parser.name
+ ) {
+ val attrs =
+ resourceHelper.obtainStyledAttributes(
+ Xml.asAttributeSet(parser),
+ R.styleable.WorkspaceSpec
+ )
+ val maxAvailableSize =
+ attrs.getDimensionPixelSize(
+ R.styleable.WorkspaceSpec_maxAvailableSize,
+ 0
+ )
+ val specType =
+ WorkspaceSpec.SpecType.values()[
+ attrs.getInt(
+ R.styleable.WorkspaceSpec_specType,
+ WorkspaceSpec.SpecType.HEIGHT.ordinal
+ )]
+ attrs.recycle()
+
+ var startPadding: SizeSpec? = null
+ var endPadding: SizeSpec? = null
+ var gutter: SizeSpec? = null
+ var cellSize: SizeSpec? = null
+
+ val limitDepth = parser.depth
+ while (
+ (parser.next().also { type = it } != XmlPullParser.END_TAG ||
+ parser.depth > limitDepth) && type != XmlPullParser.END_DOCUMENT
+ ) {
+ val attr: AttributeSet = Xml.asAttributeSet(parser)
+ if (type == XmlPullParser.START_TAG) {
+ when (parser.name) {
+ XmlTags.START_PADDING -> {
+ startPadding = SizeSpec(resourceHelper, attr)
+ }
+ XmlTags.END_PADDING -> {
+ endPadding = SizeSpec(resourceHelper, attr)
+ }
+ XmlTags.GUTTER -> {
+ gutter = SizeSpec(resourceHelper, attr)
+ }
+ XmlTags.CELL_SIZE -> {
+ cellSize = SizeSpec(resourceHelper, attr)
+ }
+ }
+ }
+ }
+
+ if (
+ startPadding == null ||
+ endPadding == null ||
+ gutter == null ||
+ cellSize == null
+ ) {
+ throw IllegalStateException(
+ "All attributes in workspaceSpec must be defined"
+ )
+ }
+
+ val workspaceSpec =
+ WorkspaceSpec(
+ maxAvailableSize,
+ specType,
+ startPadding,
+ endPadding,
+ gutter,
+ cellSize
+ )
+ if (workspaceSpec.isValid()) {
+ if (workspaceSpec.specType == WorkspaceSpec.SpecType.HEIGHT)
+ workspaceHeightSpecList.add(workspaceSpec)
+ else workspaceWidthSpecList.add(workspaceSpec)
+ } else {
+ throw IllegalStateException("Invalid workspaceSpec found.")
+ }
+ }
+ }
+
+ if (workspaceWidthSpecList.isEmpty() || workspaceHeightSpecList.isEmpty()) {
+ throw IllegalStateException(
+ "WorkspaceSpecs is incomplete - " +
+ "height list size = ${workspaceHeightSpecList.size}; " +
+ "width list size = ${workspaceWidthSpecList.size}."
+ )
+ }
+ }
+ }
+ parser.close()
+ } catch (e: Exception) {
+ when (e) {
+ is IOException,
+ is XmlPullParserException -> {
+ throw RuntimeException("Failure parsing workspaces specs file.", e)
+ }
+ else -> throw e
+ }
+ }
+ }
+}
+
+data class WorkspaceSpec(
+ val maxAvailableSize: Int,
+ val specType: SpecType,
+ val startPadding: SizeSpec,
+ val endPadding: SizeSpec,
+ val gutter: SizeSpec,
+ val cellSize: SizeSpec
+) {
+
+ enum class SpecType {
+ HEIGHT,
+ WIDTH
+ }
+
+ fun isValid(): Boolean {
+ if (maxAvailableSize <= 0) {
+ Log.e(TAG, "WorkspaceSpec#isValid - maxAvailableSize <= 0")
+ return false
+ }
+
+ // All specs need to be individually valid
+ if (!allSpecsAreValid()) {
+ Log.e(TAG, "WorkspaceSpec#isValid - !allSpecsAreValid()")
+ return false
+ }
+
+ return true
+ }
+
+ private fun allSpecsAreValid(): Boolean =
+ startPadding.isValid() && endPadding.isValid() && gutter.isValid() && cellSize.isValid()
+}
+
+class SizeSpec(resourceHelper: ResourceHelper, attrs: AttributeSet) {
+ val fixedSize: Float
+ val ofAvailableSpace: Float
+ val ofRemainderSpace: Float
+
+ init {
+ val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SpecSize)
+
+ fixedSize = getValue(styledAttrs, R.styleable.SpecSize_fixedSize)
+ ofAvailableSpace = getValue(styledAttrs, R.styleable.SpecSize_ofAvailableSpace)
+ ofRemainderSpace = getValue(styledAttrs, R.styleable.SpecSize_ofRemainderSpace)
+
+ styledAttrs.recycle()
+ }
+
+ private fun getValue(a: TypedArray, index: Int): Float {
+ if (a.getType(index) == TypedValue.TYPE_DIMENSION) {
+ return a.getDimensionPixelSize(index, 0).toFloat()
+ } else if (a.getType(index) == TypedValue.TYPE_FLOAT) {
+ return a.getFloat(index, 0f)
+ }
+ return 0f
+ }
+
+ fun isValid(): Boolean {
+ // All attributes are empty
+ if (fixedSize <= 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
+ Log.e(TAG, "SizeSpec#isValid - all attributes are empty")
+ return false
+ }
+
+ // More than one attribute is filled
+ val attrCount =
+ (if (fixedSize > 0) 1 else 0) +
+ (if (ofAvailableSpace > 0) 1 else 0) +
+ (if (ofRemainderSpace > 0) 1 else 0)
+ if (attrCount > 1) {
+ Log.e(TAG, "SizeSpec#isValid - more than one attribute is filled")
+ return false
+ }
+
+ // Values should be between 0 and 1
+ if (ofAvailableSpace !in 0f..1f || ofRemainderSpace !in 0f..1f) {
+ Log.e(TAG, "SizeSpec#isValid - values should be between 0 and 1")
+ return false
+ }
+
+ return true
+ }
+
+ override fun toString(): String {
+ return "SizeSpec(fixedSize=$fixedSize, ofAvailableSpace=$ofAvailableSpace, " +
+ "ofRemainderSpace=$ofRemainderSpace)"
+ }
+}
diff --git a/src_build_config/com/android/launcher3/BuildConfig.java b/src_build_config/com/android/launcher3/BuildConfig.java
index 9a81d3f..1f2e0e5 100644
--- a/src_build_config/com/android/launcher3/BuildConfig.java
+++ b/src_build_config/com/android/launcher3/BuildConfig.java
@@ -18,10 +18,16 @@
public final class BuildConfig {
public static final String APPLICATION_ID = "com.android.launcher3";
- public static final boolean DEBUG = false;
+
+ public static final boolean IS_STUDIO_BUILD = false;
/**
* Flag to state if the QSB is on the first screen and placed on the top,
* this can be overwritten in other launchers with a different value, if needed.
*/
public static final boolean QSB_ON_FIRST_SCREEN = true;
+
+ /**
+ * Flag to control various developer centric features
+ */
+ public static final boolean IS_DEBUG_DEVICE = false;
}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 702f343..1b743e8 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -40,7 +40,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.picker.WidgetsDiffReporter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -73,8 +72,7 @@
/**
* Returns a list of {@link WidgetsListBaseEntry}. All {@link WidgetItem} in a single row
* are sorted (based on label and user), but the overall list of
- * {@link WidgetsListBaseEntry}s is not sorted. This list is sorted at the UI when using
- * {@link WidgetsDiffReporter}
+ * {@link WidgetsListBaseEntry}s is not sorted.
*
* @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
*/
@@ -87,7 +85,7 @@
List<WidgetItem> widgetItems = entry.getValue();
String sectionName = (pkgItem.title == null) ? "" :
indexer.computeSectionName(pkgItem.title);
- result.add(new WidgetsListHeaderEntry(pkgItem, sectionName, widgetItems));
+ result.add(WidgetsListHeaderEntry.create(pkgItem, sectionName, widgetItems));
result.add(new WidgetsListContentEntry(pkgItem, sectionName, widgetItems));
}
return result;
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/DeviceFlag.java b/src_ui_overrides/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
similarity index 62%
rename from src_ui_overrides/com/android/launcher3/uioverrides/DeviceFlag.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
index 5c1ac28..68843f2 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/DeviceFlag.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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,14 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.launcher3.uioverrides.flags;
-package com.android.launcher3.uioverrides;
-
-import com.android.launcher3.config.FeatureFlags.DebugFlag;
-
-public class DeviceFlag extends DebugFlag {
-
- public DeviceFlag(String key, boolean defaultValue, String description) {
- super(key, defaultValue, description);
- }
+/**
+ * Place holder class for developer options.
+ */
+public class DeveloperOptionsFragment {
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java
new file mode 100644
index 0000000..4463adc
--- /dev/null
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -0,0 +1,58 @@
+/*
+ * 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.uioverrides.flags;
+
+import com.android.launcher3.config.FeatureFlags.BooleanFlag;
+import com.android.launcher3.config.FeatureFlags.IntFlag;
+
+import java.io.PrintWriter;
+
+/**
+ * Helper class to create various flags for launcher build. The base implementation does
+ * not provide any flagging system, and simply replies with the default value.
+ */
+public class FlagsFactory {
+
+ /**
+ * Creates a new debug flag
+ */
+ public static BooleanFlag getDebugFlag(
+ int bugId, String key, boolean defaultValue, String description) {
+ return new BooleanFlag(defaultValue);
+ }
+
+ /**
+ * Creates a new debug flag
+ */
+ public static BooleanFlag getReleaseFlag(
+ int bugId, String key, boolean defaultValueInCode, String description) {
+ return new BooleanFlag(defaultValueInCode);
+ }
+
+ /**
+ * Creates a new integer flag. Integer flags are always release flags
+ */
+ public static IntFlag getIntFlag(
+ int bugId, String key, int defaultValueInCode, String description) {
+ return new IntFlag(defaultValueInCode);
+ }
+
+ /**
+ * Dumps the current flags state to the print writer
+ */
+ public static void dump(PrintWriter pw) { }
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index 7144d65..dfbaf86 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -44,6 +44,7 @@
srcs: [
"src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
"src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
+ "src/com/android/launcher3/ui/TaplTestsLauncher3.java",
"src/com/android/launcher3/util/TestUtil.java",
"src/com/android/launcher3/util/Wait.java",
"src/com/android/launcher3/util/WidgetUtils.java",
@@ -54,7 +55,7 @@
"src/com/android/launcher3/util/rule/ShellCommandRule.java",
"src/com/android/launcher3/util/rule/SimpleActivityRule.java",
"src/com/android/launcher3/util/rule/TestStabilityRule.java",
- "src/com/android/launcher3/ui/TaplTestsLauncher3.java",
+ "src/com/android/launcher3/util/rule/TISBindRule.java",
"src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
"src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
"src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
diff --git a/tests/res/values/attrs.xml b/tests/res/values/attrs.xml
new file mode 100644
index 0000000..2310d9e
--- /dev/null
+++ b/tests/res/values/attrs.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/* Copyright 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.
+*/
+-->
+
+<!-- Attributes have to be copied to test for correct parsing of files -->
+<resources>
+ <!-- Responsive grids attributes -->
+ <declare-styleable name="WorkspaceSpec">
+ <attr name="specType" format="integer">
+ <enum name="height" value="0" />
+ <enum name="width" value="1" />
+ </attr>
+ <attr name="maxAvailableSize" format="dimension" />
+ </declare-styleable>
+
+ <declare-styleable name="SpecSize">
+ <attr name="fixedSize" format="dimension" />
+ <attr name="ofAvailableSpace" format="float" />
+ <attr name="ofRemainderSpace" format="float" />
+ </declare-styleable>
+
+</resources>
diff --git a/tests/res/xml/invalid_workspace_file_case_1.xml b/tests/res/xml/invalid_workspace_file_case_1.xml
new file mode 100644
index 0000000..0be704b
--- /dev/null
+++ b/tests/res/xml/invalid_workspace_file_case_1.xml
@@ -0,0 +1,56 @@
+<?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.
+ -->
+
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="648dp">
+ <!-- missing startPadding -->
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
+
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:specType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_2.xml b/tests/res/xml/invalid_workspace_file_case_2.xml
new file mode 100644
index 0000000..5a37d97
--- /dev/null
+++ b/tests/res/xml/invalid_workspace_file_case_2.xml
@@ -0,0 +1,59 @@
+<?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.
+ -->
+
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="648dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0125" />
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <!-- more than 1 value in one tag -->
+ <gutter
+ launcher:ofAvailableSpace="0.0125"
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
+
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:specType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_3.xml b/tests/res/xml/invalid_workspace_file_case_3.xml
new file mode 100644
index 0000000..3e68edb
--- /dev/null
+++ b/tests/res/xml/invalid_workspace_file_case_3.xml
@@ -0,0 +1,58 @@
+<?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.
+ -->
+
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="648dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0125" />
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <!-- value bigger than 1 -->
+ <cellSize
+ launcher:ofRemainderSpace="1.001" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
+
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:specType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_file.xml b/tests/res/xml/valid_workspace_file.xml
new file mode 100644
index 0000000..91a3e48
--- /dev/null
+++ b/tests/res/xml/valid_workspace_file.xml
@@ -0,0 +1,57 @@
+<?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.
+ -->
+
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="648dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0125" />
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:specType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
+
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:specType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 11363a2..c69ec2c 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -126,6 +126,9 @@
public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center";
public static final String REQUEST_WORKSPACE_COLUMNS_ROWS = "workspace-columns-rows";
+ public static final String REQUEST_WORKSPACE_CURRENT_PAGE_INDEX =
+ "workspace-current-page-index";
+
public static final String REQUEST_HOTSEAT_CELL_CENTER = "hotseat-cell-center";
public static final String REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET =
@@ -151,6 +154,8 @@
public static final String MISSING_PROMISE_ICON = "b/202985412";
public static final String TASKBAR_IN_APP_STATE = "b/227657604";
public static final String NPE_TRANSIENT_TASKBAR = "b/257549303";
+ public static final String FLAKY_BINDING = "b/270216650";
+ public static final String VIEW_AND_ACTIVITY_LEAKS = "b/260260325";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
new file mode 100644
index 0000000..0fe8bee
--- /dev/null
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -0,0 +1,290 @@
+/*
+ * 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
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Point
+import android.graphics.Rect
+import android.util.DisplayMetrics
+import android.view.Surface
+import androidx.test.core.app.ApplicationProvider
+import com.android.launcher3.util.DisplayController
+import com.android.launcher3.util.NavigationMode
+import com.android.launcher3.util.WindowBounds
+import com.android.launcher3.util.window.CachedDisplayInfo
+import com.android.launcher3.util.window.WindowManagerProxy
+import kotlin.math.max
+import kotlin.math.min
+import org.junit.After
+import org.junit.Before
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+
+/**
+ * This is an abstract class for DeviceProfile tests that create an InvariantDeviceProfile based on
+ * a real device spec.
+ *
+ * For an implementation that mocks InvariantDeviceProfile, use [FakeInvariantDeviceProfileTest]
+ */
+abstract class AbstractDeviceProfileTest {
+ protected var context: Context? = null
+ protected open val runningContext: Context = ApplicationProvider.getApplicationContext()
+ private var displayController: DisplayController = mock(DisplayController::class.java)
+ private var windowManagerProxy: WindowManagerProxy = mock(WindowManagerProxy::class.java)
+ private lateinit var originalDisplayController: DisplayController
+ private lateinit var originalWindowManagerProxy: WindowManagerProxy
+
+ @Before
+ fun setUp() {
+ val appContext: Context = ApplicationProvider.getApplicationContext()
+ originalWindowManagerProxy = WindowManagerProxy.INSTANCE.get(appContext)
+ originalDisplayController = DisplayController.INSTANCE.get(appContext)
+ WindowManagerProxy.INSTANCE.initializeForTesting(windowManagerProxy)
+ DisplayController.INSTANCE.initializeForTesting(displayController)
+ }
+
+ @After
+ fun tearDown() {
+ WindowManagerProxy.INSTANCE.initializeForTesting(originalWindowManagerProxy)
+ DisplayController.INSTANCE.initializeForTesting(originalDisplayController)
+ }
+
+ class DeviceSpec(
+ val naturalSize: Pair<Int, Int>,
+ val densityDpi: Int,
+ val statusBarNaturalPx: Int,
+ val statusBarRotatedPx: Int,
+ val gesturePx: Int,
+ val cutoutPx: Int
+ )
+
+ open val deviceSpecs =
+ mapOf(
+ "phone" to
+ DeviceSpec(
+ Pair(1080, 2400),
+ densityDpi = 420,
+ statusBarNaturalPx = 118,
+ statusBarRotatedPx = 74,
+ gesturePx = 63,
+ cutoutPx = 118
+ ),
+ "tablet" to
+ DeviceSpec(
+ Pair(2560, 1600),
+ densityDpi = 320,
+ statusBarNaturalPx = 104,
+ statusBarRotatedPx = 104,
+ gesturePx = 0,
+ cutoutPx = 0
+ ),
+ "twopanel-phone" to
+ DeviceSpec(
+ Pair(1080, 2092),
+ densityDpi = 420,
+ statusBarNaturalPx = 133,
+ statusBarRotatedPx = 110,
+ gesturePx = 63,
+ cutoutPx = 133
+ ),
+ "twopanel-tablet" to
+ DeviceSpec(
+ Pair(2208, 1840),
+ densityDpi = 420,
+ statusBarNaturalPx = 110,
+ statusBarRotatedPx = 133,
+ gesturePx = 0,
+ cutoutPx = 0
+ )
+ )
+
+ protected fun initializeVarsForPhone(
+ deviceSpec: DeviceSpec,
+ isGestureMode: Boolean = true,
+ isVerticalBar: Boolean = false
+ ) {
+ val (naturalX, naturalY) = deviceSpec.naturalSize
+ val windowsBounds = phoneWindowsBounds(deviceSpec, isGestureMode, naturalX, naturalY)
+ val displayInfo =
+ CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0, Rect(0, 0, 0, 0))
+ val perDisplayBoundsCache = mapOf(displayInfo to windowsBounds)
+
+ initializeCommonVars(
+ perDisplayBoundsCache,
+ displayInfo,
+ rotation = if (isVerticalBar) Surface.ROTATION_90 else Surface.ROTATION_0,
+ isGestureMode,
+ densityDpi = deviceSpec.densityDpi
+ )
+ }
+
+ protected fun initializeVarsForTablet(
+ deviceSpec: DeviceSpec,
+ isLandscape: Boolean = false,
+ isGestureMode: Boolean = true
+ ) {
+ val (naturalX, naturalY) = deviceSpec.naturalSize
+ val windowsBounds = tabletWindowsBounds(deviceSpec, naturalX, naturalY)
+ val displayInfo =
+ CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0, Rect(0, 0, 0, 0))
+ val perDisplayBoundsCache = mapOf(displayInfo to windowsBounds)
+
+ initializeCommonVars(
+ perDisplayBoundsCache,
+ displayInfo,
+ rotation = if (isLandscape) Surface.ROTATION_0 else Surface.ROTATION_90,
+ isGestureMode,
+ densityDpi = deviceSpec.densityDpi
+ )
+ }
+
+ protected fun initializeVarsForTwoPanel(
+ deviceTabletSpec: DeviceSpec,
+ deviceSpec: DeviceSpec,
+ isLandscape: Boolean = false,
+ isGestureMode: Boolean = true
+ ) {
+ val (tabletNaturalX, tabletNaturalY) = deviceTabletSpec.naturalSize
+ val tabletWindowsBounds =
+ tabletWindowsBounds(deviceTabletSpec, tabletNaturalX, tabletNaturalY)
+ val tabletDisplayInfo =
+ CachedDisplayInfo(
+ Point(tabletNaturalX, tabletNaturalY),
+ Surface.ROTATION_0,
+ Rect(0, 0, 0, 0)
+ )
+
+ val (phoneNaturalX, phoneNaturalY) = deviceSpec.naturalSize
+ val phoneWindowsBounds =
+ phoneWindowsBounds(deviceSpec, isGestureMode, phoneNaturalX, phoneNaturalY)
+ val phoneDisplayInfo =
+ CachedDisplayInfo(
+ Point(phoneNaturalX, phoneNaturalY),
+ Surface.ROTATION_0,
+ Rect(0, 0, 0, 0)
+ )
+
+ val perDisplayBoundsCache =
+ mapOf(tabletDisplayInfo to tabletWindowsBounds, phoneDisplayInfo to phoneWindowsBounds)
+
+ initializeCommonVars(
+ perDisplayBoundsCache,
+ tabletDisplayInfo,
+ rotation = if (isLandscape) Surface.ROTATION_0 else Surface.ROTATION_90,
+ isGestureMode,
+ densityDpi = deviceTabletSpec.densityDpi
+ )
+ }
+
+ private fun phoneWindowsBounds(
+ deviceSpec: DeviceSpec,
+ isGestureMode: Boolean,
+ naturalX: Int,
+ naturalY: Int
+ ): Array<WindowBounds> {
+ val buttonsNavHeight = Utilities.dpToPx(48f, deviceSpec.densityDpi)
+
+ val rotation0Insets =
+ Rect(
+ 0,
+ max(deviceSpec.statusBarNaturalPx, deviceSpec.cutoutPx),
+ 0,
+ if (isGestureMode) deviceSpec.gesturePx else buttonsNavHeight
+ )
+ val rotation90Insets =
+ Rect(
+ deviceSpec.cutoutPx,
+ deviceSpec.statusBarRotatedPx,
+ if (isGestureMode) 0 else buttonsNavHeight,
+ if (isGestureMode) deviceSpec.gesturePx else 0
+ )
+ val rotation180Insets =
+ Rect(
+ 0,
+ deviceSpec.statusBarNaturalPx,
+ 0,
+ max(
+ if (isGestureMode) deviceSpec.gesturePx else buttonsNavHeight,
+ deviceSpec.cutoutPx
+ )
+ )
+ val rotation270Insets =
+ Rect(
+ if (isGestureMode) 0 else buttonsNavHeight,
+ deviceSpec.statusBarRotatedPx,
+ deviceSpec.cutoutPx,
+ if (isGestureMode) deviceSpec.gesturePx else 0
+ )
+
+ return arrayOf(
+ WindowBounds(Rect(0, 0, naturalX, naturalY), rotation0Insets, Surface.ROTATION_0),
+ WindowBounds(Rect(0, 0, naturalY, naturalX), rotation90Insets, Surface.ROTATION_90),
+ WindowBounds(Rect(0, 0, naturalX, naturalY), rotation180Insets, Surface.ROTATION_180),
+ WindowBounds(Rect(0, 0, naturalY, naturalX), rotation270Insets, Surface.ROTATION_270)
+ )
+ }
+
+ private fun tabletWindowsBounds(
+ deviceSpec: DeviceSpec,
+ naturalX: Int,
+ naturalY: Int
+ ): Array<WindowBounds> {
+ val naturalInsets = Rect(0, deviceSpec.statusBarNaturalPx, 0, 0)
+ val rotatedInsets = Rect(0, deviceSpec.statusBarRotatedPx, 0, 0)
+
+ return arrayOf(
+ WindowBounds(Rect(0, 0, naturalX, naturalY), naturalInsets, Surface.ROTATION_0),
+ WindowBounds(Rect(0, 0, naturalY, naturalX), rotatedInsets, Surface.ROTATION_90),
+ WindowBounds(Rect(0, 0, naturalX, naturalY), naturalInsets, Surface.ROTATION_180),
+ WindowBounds(Rect(0, 0, naturalY, naturalX), rotatedInsets, Surface.ROTATION_270)
+ )
+ }
+
+ private fun initializeCommonVars(
+ perDisplayBoundsCache: Map<CachedDisplayInfo, Array<WindowBounds>>,
+ displayInfo: CachedDisplayInfo,
+ rotation: Int,
+ isGestureMode: Boolean = true,
+ densityDpi: Int
+ ) {
+ val windowsBounds = perDisplayBoundsCache[displayInfo]!!
+ val realBounds = windowsBounds[rotation]
+ whenever(windowManagerProxy.getDisplayInfo(ArgumentMatchers.any())).thenReturn(displayInfo)
+ whenever(windowManagerProxy.getRealBounds(ArgumentMatchers.any(), ArgumentMatchers.any()))
+ .thenReturn(realBounds)
+ whenever(windowManagerProxy.getRotation(ArgumentMatchers.any())).thenReturn(rotation)
+ whenever(windowManagerProxy.getNavigationMode(ArgumentMatchers.any()))
+ .thenReturn(
+ if (isGestureMode) NavigationMode.NO_BUTTON else NavigationMode.THREE_BUTTONS
+ )
+
+ val density = densityDpi / DisplayMetrics.DENSITY_DEFAULT.toFloat()
+ val config =
+ Configuration(runningContext.resources.configuration).apply {
+ this.densityDpi = densityDpi
+ screenWidthDp = (realBounds.bounds.width() / density).toInt()
+ screenHeightDp = (realBounds.bounds.height() / density).toInt()
+ smallestScreenWidthDp = min(screenWidthDp, screenHeightDp)
+ }
+ context = runningContext.createConfigurationContext(config)
+
+ val info = DisplayController.Info(context, windowManagerProxy, perDisplayBoundsCache)
+ whenever(displayController.info).thenReturn(info)
+ whenever(displayController.isTransientTaskbar).thenReturn(isGestureMode)
+ }
+}
diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
rename to tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index 0aecfb2..a5f33c0 100644
--- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
+++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -31,7 +31,13 @@
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when` as whenever
-abstract class DeviceProfileBaseTest {
+/**
+ * This is an abstract class for DeviceProfile tests that don't need the real Context and mock an
+ * InvariantDeviceProfile instead of creating one based on real values.
+ *
+ * For an implementation that creates InvariantDeviceProfile, use [AbstractDeviceProfileTest]
+ */
+abstract class FakeInvariantDeviceProfileTest {
protected var context: Context? = null
protected var inv: InvariantDeviceProfile? = null
@@ -120,6 +126,7 @@
horizontalMargin = FloatArray(4) { 22f }
+ allAppsStyle = R.style.AllAppsStyleDefault
allAppsCellSize =
listOf(
PointF(80f, 104f),
@@ -198,6 +205,7 @@
horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f)
+ allAppsStyle = R.style.AllAppsStyleDefault
allAppsCellSize =
listOf(
PointF(96f, 142f),
@@ -277,6 +285,7 @@
horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f)
+ allAppsStyle = R.style.AllAppsStyleDefault
allAppsCellSize =
listOf(PointF(0f, 0f), PointF(0f, 0f), PointF(68f, 104f), PointF(80f, 104f))
.toTypedArray()
diff --git a/tests/src/com/android/launcher3/LauncherPrefsTest.kt b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
index 31e8d30..41ef3de 100644
--- a/tests/src/com/android/launcher3/LauncherPrefsTest.kt
+++ b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
@@ -1,9 +1,27 @@
+/*
+ * 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
+import android.content.Context
+import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.LauncherPrefs.Companion.BOOT_AWARE_PREFS_KEY
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@@ -13,16 +31,22 @@
private val TEST_BOOLEAN_ITEM = LauncherPrefs.nonRestorableItem("1", false)
private val TEST_STRING_ITEM = LauncherPrefs.nonRestorableItem("2", "( ͡❛ ͜ʖ ͡❛)")
private val TEST_INT_ITEM = LauncherPrefs.nonRestorableItem("3", -1)
-private val TEST_CONTEXTUAL_ITEM = LauncherPrefs.backedUpItem("4") { true }
+private val TEST_CONTEXTUAL_ITEM = ContextualItem("4", true, { true }, false, Boolean::class.java)
+
+private const val TEST_DEFAULT_VALUE = "default"
+private const val TEST_PREF_KEY = "test_pref_key"
+
+private const val WAIT_TIME_IN_SECONDS = 3L
@SmallTest
@RunWith(AndroidJUnit4::class)
class LauncherPrefsTest {
- private val launcherPrefs by lazy {
- LauncherPrefs.get(InstrumentationRegistry.getInstrumentation().targetContext).apply {
- remove(TEST_BOOLEAN_ITEM, TEST_STRING_ITEM, TEST_INT_ITEM)
- }
+ private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
+ private val launcherPrefs by lazy { LauncherPrefs.get(context) }
+
+ init {
+ isBootAwareStartupDataEnabled = true
}
@Test
@@ -49,7 +73,7 @@
addListener(listener, TEST_STRING_ITEM)
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"))
- assertThat(latch.await(2, TimeUnit.SECONDS)).isTrue()
+ assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue()
remove(TEST_STRING_ITEM)
}
}
@@ -65,7 +89,7 @@
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "hello."))
// latch will be still be 1 (and await will return false) if the listener was not called
- assertThat(latch.await(2, TimeUnit.SECONDS)).isFalse()
+ assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse()
remove(TEST_STRING_ITEM)
}
}
@@ -82,7 +106,7 @@
TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"),
TEST_BOOLEAN_ITEM.to(!TEST_BOOLEAN_ITEM.defaultValue)
)
- assertThat(latch.await(2, TimeUnit.SECONDS)).isTrue()
+ assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue()
removeListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
latch = CountDownLatch(1)
@@ -93,7 +117,7 @@
)
remove(TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
- assertThat(latch.await(2, TimeUnit.SECONDS)).isFalse()
+ assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse()
}
}
@@ -151,4 +175,145 @@
fun get_contextualItem_returnsCorrectDefault() {
assertThat(launcherPrefs.get(TEST_CONTEXTUAL_ITEM)).isTrue()
}
+
+ @Test
+ fun getItemSharedPrefFile_forNonRestorableItem_isCorrect() {
+ val nonRestorableItem = LauncherPrefs.nonRestorableItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE)
+ assertThat(nonRestorableItem.sharedPrefFile).isEqualTo(LauncherFiles.DEVICE_PREFERENCES_KEY)
+ }
+
+ @Test
+ fun getItemSharedPrefFile_forBackedUpItem_isCorrect() {
+ val backedUpItem = LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE)
+ assertThat(backedUpItem.sharedPrefFile).isEqualTo(LauncherFiles.SHARED_PREFERENCES_KEY)
+ }
+
+ @Test
+ fun put_bootAwareItem_updatesDeviceProtectedStorage() {
+ val bootAwareItem =
+ LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
+
+ val bootAwarePrefs: SharedPreferences =
+ context
+ .createDeviceProtectedStorageContext()
+ .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
+ bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
+
+ launcherPrefs.putSync(bootAwareItem.to(bootAwareItem.defaultValue))
+ assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
+
+ launcherPrefs.removeSync(bootAwareItem)
+ }
+
+ @Test
+ fun put_bootAwareItem_updatesEncryptedStorage() {
+ val bootAwareItem =
+ LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
+
+ val encryptedPrefs: SharedPreferences =
+ context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
+ encryptedPrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
+
+ launcherPrefs.putSync(bootAwareItem.to(TEST_STRING_ITEM.defaultValue))
+ assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
+
+ launcherPrefs.removeSync(bootAwareItem)
+ }
+
+ @Test
+ fun remove_bootAwareItem_removesFromDeviceProtectedStorage() {
+ val bootAwareItem =
+ LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
+
+ val bootAwarePrefs: SharedPreferences =
+ context
+ .createDeviceProtectedStorageContext()
+ .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
+
+ bootAwarePrefs
+ .edit()
+ .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
+ .commit()
+
+ launcherPrefs.removeSync(bootAwareItem)
+ assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
+ }
+
+ @Test
+ fun remove_bootAwareItem_removesFromEncryptedStorage() {
+ val bootAwareItem =
+ LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
+
+ val encryptedPrefs: SharedPreferences =
+ context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
+
+ encryptedPrefs
+ .edit()
+ .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
+ .commit()
+
+ launcherPrefs.removeSync(bootAwareItem)
+ assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
+ }
+
+ @Test
+ fun migrate_bootAwareItemsToDeviceProtectedStorage_worksAsIntended() {
+ val bootAwareItem =
+ LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE, isBootAware = true)
+ launcherPrefs.removeSync(bootAwareItem)
+
+ val bootAwarePrefs: SharedPreferences =
+ context
+ .createDeviceProtectedStorageContext()
+ .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
+
+ if (bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)) {
+ bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
+ }
+
+ val encryptedPrefs: SharedPreferences =
+ context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
+
+ encryptedPrefs
+ .edit()
+ .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
+ .commit()
+
+ launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
+ assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
+
+ launcherPrefs.removeSync(bootAwareItem)
+ }
+
+ @Test
+ fun migrate_onlyEncryptedItemsToDeviceProtectedStorage_doesNotHappen() {
+ val onlyEncryptedItem =
+ LauncherPrefs.backedUpItem(
+ TEST_PREF_KEY + "_",
+ TEST_DEFAULT_VALUE + "_",
+ isBootAware = false
+ )
+
+ val bootAwarePrefs: SharedPreferences =
+ context
+ .createDeviceProtectedStorageContext()
+ .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
+
+ if (bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)) {
+ bootAwarePrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
+ }
+
+ val encryptedPrefs: SharedPreferences =
+ context.getSharedPreferences(onlyEncryptedItem.sharedPrefFile, Context.MODE_PRIVATE)
+
+ encryptedPrefs
+ .edit()
+ .putString(onlyEncryptedItem.sharedPrefKey, onlyEncryptedItem.defaultValue)
+ .commit()
+
+ launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
+ assertThat(bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)).isFalse()
+
+ encryptedPrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
+ }
}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index 3443fd9..c2fe3de 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -33,6 +33,7 @@
import com.android.launcher3.celllayout.testcases.SimpleReorderCase;
import com.android.launcher3.tapl.Widget;
import com.android.launcher3.tapl.WidgetResizeFrame;
+import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.util.rule.ShellCommandRule;
@@ -114,7 +115,18 @@
new FavoriteItemsTransaction(mTargetContext, this);
transaction = buildWorkspaceFromBoards(testCase.mStart, transaction);
transaction.commit();
- waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
+ // resetLoaderState triggers the launcher to start loading the workspace which allows
+ // waitForLauncherCondition to wait for that condition, otherwise the condition would
+ // always be true and it wouldn't wait for the changes to be applied.
+ resetLoaderState();
+ Log.d(TestProtocol.FLAKY_BINDING, "waiting for: isWorkspaceLoading=false");
+ waitForLauncherCondition("Workspace didn't finish loading", l -> {
+ boolean isWorkspaceLoading = l.isWorkspaceLoading();
+
+ Log.d(TestProtocol.FLAKY_BINDING, "checking: isWorkspaceLoading=" + isWorkspaceLoading);
+
+ return !isWorkspaceLoading;
+ });
Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.getCellX(),
mainWidgetCellPos.getCellY());
assertNotNull(widget);
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index a85fa3a..f24f0da 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -618,8 +618,6 @@
assertThat(locMap[testPackage3]).isEqualTo(1)
assertThat(locMap[testPackage4]).isEqualTo(1)
assertThat(locMap[testPackage5]).isEqualTo(2)
-
- disableNewMigrationLogic()
}
/**
@@ -684,7 +682,6 @@
assertThat(locMap[testPackage3]).isEqualTo(0)
assertThat(locMap[testPackage4]).isEqualTo(0)
assertThat(locMap[testPackage5]).isEqualTo(0)
- disableNewMigrationLogic()
}
/** Migrating from a larger grid to a smaller, we reflow from page 0 */
@@ -745,25 +742,9 @@
assertThat(locMap[testPackage3]).isEqualTo(0)
assertThat(locMap[testPackage4]).isEqualTo(0)
assertThat(locMap[testPackage5]).isEqualTo(0)
-
- disableNewMigrationLogic()
}
private fun enableNewMigrationLogic(srcGridSize: String) {
- context
- .getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
- .edit()
- .putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, true)
- .commit()
LauncherPrefs.get(context).putSync(WORKSPACE_SIZE.to(srcGridSize))
- FeatureFlags.initialize(context)
- }
-
- private fun disableNewMigrationLogic() {
- context
- .getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
- .edit()
- .putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, false)
- .commit()
}
}
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 6444ef6..7ab86ad 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -18,6 +18,9 @@
import static androidx.test.InstrumentationRegistry.getContext;
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_ID;
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER;
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_SOURCE;
import static com.android.launcher3.LauncherSettings.Favorites.CELLX;
import static com.android.launcher3.LauncherSettings.Favorites.CELLY;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
@@ -30,9 +33,13 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.OPTIONS;
import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID;
+import static com.android.launcher3.LauncherSettings.Favorites.RANK;
import static com.android.launcher3.LauncherSettings.Favorites.RESTORED;
import static com.android.launcher3.LauncherSettings.Favorites.SCREEN;
+import static com.android.launcher3.LauncherSettings.Favorites.SPANX;
+import static com.android.launcher3.LauncherSettings.Favorites.SPANY;
import static com.android.launcher3.LauncherSettings.Favorites.TITLE;
import static com.android.launcher3.LauncherSettings.Favorites._ID;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
@@ -92,7 +99,9 @@
mCursor = new MatrixCursor(new String[] {
ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE,
_ID, CONTAINER, ITEM_TYPE, PROFILE_ID,
- SCREEN, CELLX, CELLY, RESTORED, INTENT
+ SCREEN, CELLX, CELLY, RESTORED, INTENT,
+ APPWIDGET_ID, APPWIDGET_PROVIDER, SPANX,
+ SPANY, RANK, OPTIONS, APPWIDGET_SOURCE
});
UserManagerState ums = new UserManagerState();
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
new file mode 100644
index 0000000..af31e93
--- /dev/null
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -0,0 +1,1650 @@
+/*
+ * 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.nonquickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.InvariantDeviceProfile
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for DeviceProfile. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
+
+ @Test
+ fun phonePortrait3Button() {
+ initializeVarsForPhone(deviceSpecs["phone"]!!, isGestureMode = false)
+ val dp = getDeviceProfileForGrid("5_by_5")
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:false\n" +
+ "\tisPhone:true\n" +
+ "\ttransposeLayoutWithOrientation:true\n" +
+ "\tisGestureMode:false\n" +
+ "\tisLandscape:false\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 1080.0px (411.42856dp)\n" +
+ "\theightPx: 2400.0px (914.2857dp)\n" +
+ "\tavailableWidthPx: 1080.0px (411.42856dp)\n" +
+ "\tavailableHeightPx: 2156.0px (821.3333dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 118.0px (44.95238dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 126.0px (48.0dp)\n" +
+ "\taspectRatio:2.2222223\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 5\n" +
+ "\tinv.numSearchContainerColumns: 5\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 165.0px (62.857143dp)\n" +
+ "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+ "\tgetCellSize().x: 207.0px (78.85714dp)\n" +
+ "\tgetCellSize().y: 379.0px (144.38095dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 21.0px (8.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 28.0px (10.666667dp)\n" +
+ "\tcellLayoutPaddingPx.right: 21.0px (8.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
+ "\ticonSizePx: 147.0px (56.0dp)\n" +
+ "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
+ "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\tinv.numFolderRows: 4\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
+ "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
+ "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
+ "\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 146.0px (55.61905dp)\n" +
+ "\tbottomSheetOpenDuration: 267\n" +
+ "\tbottomSheetCloseDuration: 267\n" +
+ "\tbottomSheetWorkspaceScale: 1.0\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+ "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+ "\tallAppsOpenDuration: 600\n" +
+ "\tallAppsCloseDuration: 300\n" +
+ "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+ "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+ "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 5\n" +
+ "\tallAppsLeftRightPadding: 21.0px (8.0dp)\n" +
+ "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+ "\thotseatBarSizePx: 294.0px (112.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 5\n" +
+ "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+ "\thotseatBarBottomSpacePx: 147.0px (56.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 200.0px (76.190475dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 128.0px (48.761906dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 21.0px (8.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 21.0px (8.0dp)\n" +
+ "\tnumShownHotseatIcons: 5\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:false\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.left: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.right: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.bottom: 203.0px (77.333336dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 722.0px (275.0476dp)\n" +
+ "\tunscaled extraSpace: 722.0px (275.0476dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 126.0px (48.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 84.0px (32.0dp)\n" +
+ "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1906.0px (726.0952dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.77572966px (0.29551607dp)\n" +
+ "\tgetCellLayoutHeight(): 1953.0px (744.0dp)\n" +
+ "\tgetCellLayoutWidth(): 1080.0px (411.42856dp)\n"
+ )
+ }
+
+ @Test
+ fun phonePortrait() {
+ initializeVarsForPhone(deviceSpecs["phone"]!!)
+ val dp = getDeviceProfileForGrid("5_by_5")
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:false\n" +
+ "\tisPhone:true\n" +
+ "\ttransposeLayoutWithOrientation:true\n" +
+ "\tisGestureMode:true\n" +
+ "\tisLandscape:false\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 1080.0px (411.42856dp)\n" +
+ "\theightPx: 2400.0px (914.2857dp)\n" +
+ "\tavailableWidthPx: 1080.0px (411.42856dp)\n" +
+ "\tavailableHeightPx: 2219.0px (845.3333dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 118.0px (44.95238dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 63.0px (24.0dp)\n" +
+ "\taspectRatio:2.2222223\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 5\n" +
+ "\tinv.numSearchContainerColumns: 5\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 165.0px (62.857143dp)\n" +
+ "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+ "\tgetCellSize().x: 207.0px (78.85714dp)\n" +
+ "\tgetCellSize().y: 383.0px (145.90475dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 21.0px (8.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 28.0px (10.666667dp)\n" +
+ "\tcellLayoutPaddingPx.right: 21.0px (8.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
+ "\ticonSizePx: 147.0px (56.0dp)\n" +
+ "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
+ "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\tinv.numFolderRows: 4\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
+ "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
+ "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
+ "\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 146.0px (55.61905dp)\n" +
+ "\tbottomSheetOpenDuration: 267\n" +
+ "\tbottomSheetCloseDuration: 267\n" +
+ "\tbottomSheetWorkspaceScale: 1.0\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+ "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+ "\tallAppsOpenDuration: 600\n" +
+ "\tallAppsCloseDuration: 300\n" +
+ "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+ "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+ "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 5\n" +
+ "\tallAppsLeftRightPadding: 21.0px (8.0dp)\n" +
+ "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+ "\thotseatBarSizePx: 273.0px (104.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 5\n" +
+ "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+ "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 200.0px (76.190475dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 107.0px (40.761906dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 21.0px (8.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 21.0px (8.0dp)\n" +
+ "\tnumShownHotseatIcons: 5\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:false\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.left: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.right: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.bottom: 245.0px (93.333336dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 743.0px (283.0476dp)\n" +
+ "\tunscaled extraSpace: 743.0px (283.0476dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 63.0px (24.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 84.0px (32.0dp)\n" +
+ "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1927.0px (734.0952dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.7781155px (0.29642496dp)\n" +
+ "\tgetCellLayoutHeight(): 1974.0px (752.0dp)\n" +
+ "\tgetCellLayoutWidth(): 1080.0px (411.42856dp)\n"
+ )
+ }
+
+ @Test
+ fun phoneVerticalBar3Button() {
+ initializeVarsForPhone(deviceSpecs["phone"]!!, isVerticalBar = true, isGestureMode = false)
+ val dp = getDeviceProfileForGrid("5_by_5")
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:false\n" +
+ "\tisPhone:true\n" +
+ "\ttransposeLayoutWithOrientation:true\n" +
+ "\tisGestureMode:false\n" +
+ "\tisLandscape:true\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 2400.0px (914.2857dp)\n" +
+ "\theightPx: 1080.0px (411.42856dp)\n" +
+ "\tavailableWidthPx: 2156.0px (821.3333dp)\n" +
+ "\tavailableHeightPx: 1006.0px (383.2381dp)\n" +
+ "\tmInsets.left: 118.0px (44.95238dp)\n" +
+ "\tmInsets.top: 74.0px (28.190475dp)\n" +
+ "\tmInsets.right: 126.0px (48.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:2.2222223\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 5\n" +
+ "\tinv.numSearchContainerColumns: 5\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+ "\tcellHeightPx: 166.0px (63.238094dp)\n" +
+ "\tgetCellSize().x: 368.0px (140.19048dp)\n" +
+ "\tgetCellSize().y: 193.0px (73.52381dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 53.0px (20.190475dp)\n" +
+ "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 53.0px (20.190475dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 40.0px (15.238095dp)\n" +
+ "\ticonSizePx: 147.0px (56.0dp)\n" +
+ "\ticonTextSizePx: 0.0px (0.0dp)\n" +
+ "\ticonDrawablePaddingPx: 0.0px (0.0dp)\n" +
+ "\tinv.numFolderRows: 4\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 142.0px (54.095238dp)\n" +
+ "\tfolderCellHeightPx: 168.0px (64.0dp)\n" +
+ "\tfolderChildIconSizePx: 108.0px (41.142857dp)\n" +
+ "\tfolderChildTextSizePx: 28.0px (10.666667dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 7.0px (2.6666667dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 114.0px (43.42857dp)\n" +
+ "\tbottomSheetOpenDuration: 267\n" +
+ "\tbottomSheetCloseDuration: 267\n" +
+ "\tbottomSheetWorkspaceScale: 1.0\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+ "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+ "\tallAppsOpenDuration: 600\n" +
+ "\tallAppsCloseDuration: 300\n" +
+ "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+ "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 321.0px (122.28571dp)\n" +
+ "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 5\n" +
+ "\tallAppsLeftRightPadding: 0.0px (0.0dp)\n" +
+ "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+ "\thotseatBarSizePx: 252.0px (96.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 5\n" +
+ "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+ "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 63.0px (24.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 42.0px (16.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 118.0px (44.95238dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 64.0px (24.380953dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 49.0px (18.666666dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 42.0px (16.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 189.0px (72.0dp)\n" +
+ "\tnumShownHotseatIcons: 5\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:false\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.left: 10.0px (3.8095238dp)\n" +
+ "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.right: 199.0px (75.809525dp)\n" +
+ "\tworkspacePadding.bottom: 0.0px (0.0dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 136.0px (51.809525dp)\n" +
+ "\tunscaled extraSpace: 136.0px (51.809525dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 16.0px (6.095238dp)\n" +
+ "\tdropTargetBarSizePx: 95.0px (36.190475dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 16.0px (6.095238dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1008.0px (384.0dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.8021869px (0.305595dp)\n" +
+ "\tgetCellLayoutHeight(): 1006.0px (383.2381dp)\n" +
+ "\tgetCellLayoutWidth(): 1947.0px (741.7143dp)\n"
+ )
+ }
+
+ @Test
+ fun phoneVerticalBar() {
+ initializeVarsForPhone(deviceSpecs["phone"]!!, isVerticalBar = true)
+ val dp = getDeviceProfileForGrid("5_by_5")
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:false\n" +
+ "\tisPhone:true\n" +
+ "\ttransposeLayoutWithOrientation:true\n" +
+ "\tisGestureMode:true\n" +
+ "\tisLandscape:true\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 2400.0px (914.2857dp)\n" +
+ "\theightPx: 1080.0px (411.42856dp)\n" +
+ "\tavailableWidthPx: 2282.0px (869.3333dp)\n" +
+ "\tavailableHeightPx: 943.0px (359.2381dp)\n" +
+ "\tmInsets.left: 118.0px (44.95238dp)\n" +
+ "\tmInsets.top: 74.0px (28.190475dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 63.0px (24.0dp)\n" +
+ "\taspectRatio:2.2222223\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 5\n" +
+ "\tinv.numSearchContainerColumns: 5\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+ "\tcellHeightPx: 166.0px (63.238094dp)\n" +
+ "\tgetCellSize().x: 393.0px (149.71428dp)\n" +
+ "\tgetCellSize().y: 180.0px (68.57143dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 53.0px (20.190475dp)\n" +
+ "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 53.0px (20.190475dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 40.0px (15.238095dp)\n" +
+ "\ticonSizePx: 147.0px (56.0dp)\n" +
+ "\ticonTextSizePx: 0.0px (0.0dp)\n" +
+ "\ticonDrawablePaddingPx: 0.0px (0.0dp)\n" +
+ "\tinv.numFolderRows: 4\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 128.0px (48.761906dp)\n" +
+ "\tfolderCellHeightPx: 152.0px (57.904762dp)\n" +
+ "\tfolderChildIconSizePx: 98.0px (37.333332dp)\n" +
+ "\tfolderChildTextSizePx: 25.0px (9.523809dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 6.0px (2.2857144dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 114.0px (43.42857dp)\n" +
+ "\tbottomSheetOpenDuration: 267\n" +
+ "\tbottomSheetCloseDuration: 267\n" +
+ "\tbottomSheetWorkspaceScale: 1.0\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+ "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+ "\tallAppsOpenDuration: 600\n" +
+ "\tallAppsCloseDuration: 300\n" +
+ "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+ "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 321.0px (122.28571dp)\n" +
+ "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 5\n" +
+ "\tallAppsLeftRightPadding: 0.0px (0.0dp)\n" +
+ "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+ "\thotseatBarSizePx: 252.0px (96.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 5\n" +
+ "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+ "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 63.0px (24.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 42.0px (16.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 118.0px (44.95238dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 64.0px (24.380953dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 112.0px (42.666668dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 42.0px (16.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 63.0px (24.0dp)\n" +
+ "\tnumShownHotseatIcons: 5\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:false\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.left: 10.0px (3.8095238dp)\n" +
+ "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.right: 199.0px (75.809525dp)\n" +
+ "\tworkspacePadding.bottom: 0.0px (0.0dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 73.0px (27.809525dp)\n" +
+ "\tunscaled extraSpace: 73.0px (27.809525dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 63.0px (24.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 16.0px (6.095238dp)\n" +
+ "\tdropTargetBarSizePx: 95.0px (36.190475dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 16.0px (6.095238dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 952.0px (362.66666dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.79639447px (0.30338836dp)\n" +
+ "\tgetCellLayoutHeight(): 943.0px (359.2381dp)\n" +
+ "\tgetCellLayoutWidth(): 2073.0px (789.7143dp)\n"
+ )
+ }
+
+ @Test
+ fun tabletLandscape3Button() {
+ initializeVarsForTablet(deviceSpecs["tablet"]!!, isLandscape = true, isGestureMode = false)
+ val dp = getDeviceProfileForGrid("6_by_5")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.0 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:false\n" +
+ "\tisLandscape:true\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 2560.0px (1280.0dp)\n" +
+ "\theightPx: 1600.0px (800.0dp)\n" +
+ "\tavailableWidthPx: 2560.0px (1280.0dp)\n" +
+ "\tavailableHeightPx: 1496.0px (748.0dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 104.0px (52.0dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.6\n" +
+ "\tisScalableGrid:true\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 6\n" +
+ "\tinv.numSearchContainerColumns: 3\n" +
+ "\tminCellSize: PointF(120.0, 104.0)dp\n" +
+ "\tcellWidthPx: 240.0px (120.0dp)\n" +
+ "\tcellHeightPx: 208.0px (104.0dp)\n" +
+ "\tgetCellSize().x: 240.0px (120.0dp)\n" +
+ "\tgetCellSize().y: 208.0px (104.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 128.0px (64.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 32.0px (16.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 59.0px (29.5dp)\n" +
+ "\tcellLayoutPaddingPx.top: 25.0px (12.5dp)\n" +
+ "\tcellLayoutPaddingPx.right: 59.0px (29.5dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
+ "\ticonSizePx: 120.0px (60.0dp)\n" +
+ "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+ "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 3\n" +
+ "\tfolderCellWidthPx: 397.0px (198.5dp)\n" +
+ "\tfolderCellHeightPx: 371.0px (185.5dp)\n" +
+ "\tfolderChildIconSizePx: 99.0px (49.5dp)\n" +
+ "\tfolderChildTextSizePx: 23.0px (11.5dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 80.0px (40.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+ "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+ "\tbottomSheetTopPadding: 104.0px (52.0dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 1496.0px (748.0dp)\n" +
+ "\tallAppsTopPadding: 104.0px (52.0dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+ "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
+ "\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 6\n" +
+ "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 412.0px (206.0dp)\n" +
+ "\thotseatBarSizePx: 200.0px (100.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 4\n" +
+ "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+ "\thotseatBarBottomSpacePx: 80.0px (40.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 668.0px (334.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 668.0px (334.0dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 100.0px (50.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 1224.0px (612.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 240.0px (120.0dp)\n" +
+ "\tworkspacePadding.left: 181.0px (90.5dp)\n" +
+ "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.right: 181.0px (90.5dp)\n" +
+ "\tworkspacePadding.bottom: 244.0px (122.0dp)\n" +
+ "\ticonScale: 1.0px (0.5dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+ "\textraSpace: 80.0px (40.0dp)\n" +
+ "\tunscaled extraSpace: 80.0px (40.0dp)\n" +
+ "\tmaxEmptySpace: 200.0px (100.0dp)\n" +
+ "\tworkspaceTopPadding: 25.0px (12.5dp)\n" +
+ "\tworkspaceBottomPadding: 55.0px (27.5dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 64.0px (32.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)\n" +
+ "\tgetCellLayoutHeight(): 1252.0px (626.0dp)\n" +
+ "\tgetCellLayoutWidth(): 2198.0px (1099.0dp)\n"
+ )
+ }
+
+ @Test
+ fun tabletLandscape() {
+ initializeVarsForTablet(deviceSpecs["tablet"]!!, isLandscape = true)
+ val dp = getDeviceProfileForGrid("6_by_5")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.0 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:true\n" +
+ "\tisLandscape:true\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 2560.0px (1280.0dp)\n" +
+ "\theightPx: 1600.0px (800.0dp)\n" +
+ "\tavailableWidthPx: 2560.0px (1280.0dp)\n" +
+ "\tavailableHeightPx: 1496.0px (748.0dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 104.0px (52.0dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.6\n" +
+ "\tisScalableGrid:true\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 6\n" +
+ "\tinv.numSearchContainerColumns: 3\n" +
+ "\tminCellSize: PointF(120.0, 104.0)dp\n" +
+ "\tcellWidthPx: 240.0px (120.0dp)\n" +
+ "\tcellHeightPx: 208.0px (104.0dp)\n" +
+ "\tgetCellSize().x: 240.0px (120.0dp)\n" +
+ "\tgetCellSize().y: 208.0px (104.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 128.0px (64.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 32.0px (16.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 59.0px (29.5dp)\n" +
+ "\tcellLayoutPaddingPx.top: 25.0px (12.5dp)\n" +
+ "\tcellLayoutPaddingPx.right: 59.0px (29.5dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
+ "\ticonSizePx: 120.0px (60.0dp)\n" +
+ "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+ "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 3\n" +
+ "\tfolderCellWidthPx: 397.0px (198.5dp)\n" +
+ "\tfolderCellHeightPx: 371.0px (185.5dp)\n" +
+ "\tfolderChildIconSizePx: 99.0px (49.5dp)\n" +
+ "\tfolderChildTextSizePx: 23.0px (11.5dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 80.0px (40.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+ "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+ "\tbottomSheetTopPadding: 104.0px (52.0dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 1496.0px (748.0dp)\n" +
+ "\tallAppsTopPadding: 104.0px (52.0dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+ "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
+ "\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 6\n" +
+ "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 412.0px (206.0dp)\n" +
+ "\thotseatBarSizePx: 200.0px (100.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 4\n" +
+ "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+ "\thotseatBarBottomSpacePx: 80.0px (40.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 668.0px (334.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 668.0px (334.0dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 100.0px (50.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 1224.0px (612.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 240.0px (120.0dp)\n" +
+ "\tworkspacePadding.left: 181.0px (90.5dp)\n" +
+ "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+ "\tworkspacePadding.right: 181.0px (90.5dp)\n" +
+ "\tworkspacePadding.bottom: 244.0px (122.0dp)\n" +
+ "\ticonScale: 1.0px (0.5dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+ "\textraSpace: 80.0px (40.0dp)\n" +
+ "\tunscaled extraSpace: 80.0px (40.0dp)\n" +
+ "\tmaxEmptySpace: 200.0px (100.0dp)\n" +
+ "\tworkspaceTopPadding: 25.0px (12.5dp)\n" +
+ "\tworkspaceBottomPadding: 55.0px (27.5dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 64.0px (32.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)\n" +
+ "\tgetCellLayoutHeight(): 1252.0px (626.0dp)\n" +
+ "\tgetCellLayoutWidth(): 2198.0px (1099.0dp)\n"
+ )
+ }
+
+ @Test
+ fun tabletPortrait3Button() {
+ initializeVarsForTablet(deviceSpecs["tablet"]!!, isGestureMode = false)
+ val dp = getDeviceProfileForGrid("6_by_5")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.0 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:false\n" +
+ "\tisLandscape:false\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 1600.0px (800.0dp)\n" +
+ "\theightPx: 2560.0px (1280.0dp)\n" +
+ "\tavailableWidthPx: 1600.0px (800.0dp)\n" +
+ "\tavailableHeightPx: 2456.0px (1228.0dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 104.0px (52.0dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.6\n" +
+ "\tisScalableGrid:true\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 6\n" +
+ "\tinv.numSearchContainerColumns: 3\n" +
+ "\tminCellSize: PointF(102.0, 120.0)dp\n" +
+ "\tcellWidthPx: 204.0px (102.0dp)\n" +
+ "\tcellHeightPx: 240.0px (120.0dp)\n" +
+ "\tgetCellSize().x: 204.0px (102.0dp)\n" +
+ "\tgetCellSize().y: 240.0px (120.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 32.0px (16.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 128.0px (64.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 72.0px (36.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 72.0px (36.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 72.0px (36.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
+ "\ticonSizePx: 120.0px (60.0dp)\n" +
+ "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+ "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 3\n" +
+ "\tfolderCellWidthPx: 408.0px (204.0dp)\n" +
+ "\tfolderCellHeightPx: 648.0px (324.0dp)\n" +
+ "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
+ "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 163.0px (81.5dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+ "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+ "\tbottomSheetTopPadding: 704.0px (352.0dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 1810.0px (905.0dp)\n" +
+ "\tallAppsTopPadding: 750.0px (375.0dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+ "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
+ "\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 6\n" +
+ "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 152.0px (76.0dp)\n" +
+ "\thotseatBarSizePx: 272.0px (136.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 6\n" +
+ "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+ "\thotseatBarBottomSpacePx: 152.0px (76.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 216.0px (108.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 137.0px (68.5dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 150.0px (75.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 150.0px (75.0dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 116.0px (58.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 1300.0px (650.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 108.0px (54.0dp)\n" +
+ "\tworkspacePadding.left: 36.0px (18.0dp)\n" +
+ "\tworkspacePadding.top: 132.0px (66.0dp)\n" +
+ "\tworkspacePadding.right: 36.0px (18.0dp)\n" +
+ "\tworkspacePadding.bottom: 468.0px (234.0dp)\n" +
+ "\ticonScale: 1.0px (0.5dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+ "\textraSpace: 424.0px (212.0dp)\n" +
+ "\tunscaled extraSpace: 424.0px (212.0dp)\n" +
+ "\tmaxEmptySpace: 19998.0px (9999.0dp)\n" +
+ "\tworkspaceTopPadding: 204.0px (102.0dp)\n" +
+ "\tworkspaceBottomPadding: 220.0px (110.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 220.0px (110.0dp)\n" +
+ "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 96.0px (48.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)\n" +
+ "\tgetCellLayoutHeight(): 1856.0px (928.0dp)\n" +
+ "\tgetCellLayoutWidth(): 1528.0px (764.0dp)\n"
+ )
+ }
+
+ @Test
+ fun tabletPortrait() {
+ initializeVarsForTablet(deviceSpecs["tablet"]!!)
+ val dp = getDeviceProfileForGrid("6_by_5")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.0 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:true\n" +
+ "\tisLandscape:false\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:false\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 1600.0px (800.0dp)\n" +
+ "\theightPx: 2560.0px (1280.0dp)\n" +
+ "\tavailableWidthPx: 1600.0px (800.0dp)\n" +
+ "\tavailableHeightPx: 2456.0px (1228.0dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 104.0px (52.0dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.6\n" +
+ "\tisScalableGrid:true\n" +
+ "\tinv.numRows: 5\n" +
+ "\tinv.numColumns: 6\n" +
+ "\tinv.numSearchContainerColumns: 3\n" +
+ "\tminCellSize: PointF(102.0, 120.0)dp\n" +
+ "\tcellWidthPx: 204.0px (102.0dp)\n" +
+ "\tcellHeightPx: 240.0px (120.0dp)\n" +
+ "\tgetCellSize().x: 204.0px (102.0dp)\n" +
+ "\tgetCellSize().y: 240.0px (120.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 32.0px (16.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 128.0px (64.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 72.0px (36.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 72.0px (36.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 72.0px (36.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
+ "\ticonSizePx: 120.0px (60.0dp)\n" +
+ "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+ "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 3\n" +
+ "\tfolderCellWidthPx: 408.0px (204.0dp)\n" +
+ "\tfolderCellHeightPx: 648.0px (324.0dp)\n" +
+ "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
+ "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 163.0px (81.5dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+ "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+ "\tbottomSheetTopPadding: 704.0px (352.0dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 0.0\n" +
+ "\tallAppsShiftRange: 1810.0px (905.0dp)\n" +
+ "\tallAppsTopPadding: 750.0px (375.0dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+ "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+ "\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
+ "\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
+ "\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 6\n" +
+ "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 152.0px (76.0dp)\n" +
+ "\thotseatBarSizePx: 272.0px (136.0dp)\n" +
+ "\tinv.hotseatColumnSpan: 6\n" +
+ "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+ "\thotseatBarBottomSpacePx: 152.0px (76.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 216.0px (108.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 137.0px (68.5dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 150.0px (75.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 150.0px (75.0dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 116.0px (58.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 1300.0px (650.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 108.0px (54.0dp)\n" +
+ "\tworkspacePadding.left: 36.0px (18.0dp)\n" +
+ "\tworkspacePadding.top: 132.0px (66.0dp)\n" +
+ "\tworkspacePadding.right: 36.0px (18.0dp)\n" +
+ "\tworkspacePadding.bottom: 468.0px (234.0dp)\n" +
+ "\ticonScale: 1.0px (0.5dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+ "\textraSpace: 424.0px (212.0dp)\n" +
+ "\tunscaled extraSpace: 424.0px (212.0dp)\n" +
+ "\tmaxEmptySpace: 19998.0px (9999.0dp)\n" +
+ "\tworkspaceTopPadding: 204.0px (102.0dp)\n" +
+ "\tworkspaceBottomPadding: 220.0px (110.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 220.0px (110.0dp)\n" +
+ "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 96.0px (48.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)\n" +
+ "\tgetCellLayoutHeight(): 1856.0px (928.0dp)\n" +
+ "\tgetCellLayoutWidth(): 1528.0px (764.0dp)\n"
+ )
+ }
+
+ @Test
+ fun twoPanelLandscape3Button() {
+ initializeVarsForTwoPanel(
+ deviceSpecs["twopanel-tablet"]!!,
+ deviceSpecs["twopanel-phone"]!!,
+ isLandscape = true,
+ isGestureMode = false
+ )
+ val dp = getDeviceProfileForGrid("4_by_4")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:false\n" +
+ "\tisLandscape:true\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:true\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 2208.0px (841.1429dp)\n" +
+ "\theightPx: 1840.0px (700.9524dp)\n" +
+ "\tavailableWidthPx: 2208.0px (841.1429dp)\n" +
+ "\tavailableHeightPx: 1730.0px (659.0476dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 110.0px (41.904762dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.2\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 4\n" +
+ "\tinv.numColumns: 4\n" +
+ "\tinv.numSearchContainerColumns: 4\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+ "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tgetCellSize().x: 270.0px (102.85714dp)\n" +
+ "\tgetCellSize().y: 342.0px (130.28572dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+ "\ticonSizePx: 141.0px (53.714287dp)\n" +
+ "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+ "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+ "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 110.0px (41.904762dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 1.0\n" +
+ "\tallAppsShiftRange: 1730.0px (659.0476dp)\n" +
+ "\tallAppsTopPadding: 110.0px (41.904762dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+ "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 8\n" +
+ "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 183.0px (69.71429dp)\n" +
+ "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+ "\tinv.hotseatColumnSpan: 4\n" +
+ "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+ "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 116.0px (44.190475dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 113.0px (43.04762dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 113.0px (43.04762dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.top: 30.0px (11.428572dp)\n" +
+ "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 478.0px (182.09525dp)\n" +
+ "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)\n" +
+ "\tgetCellLayoutHeight(): 1370.0px (521.9048dp)\n" +
+ "\tgetCellLayoutWidth(): 1083.0px (412.57144dp)\n"
+ )
+ }
+
+ @Test
+ fun twoPanelLandscape() {
+ initializeVarsForTwoPanel(
+ deviceSpecs["twopanel-tablet"]!!,
+ deviceSpecs["twopanel-phone"]!!,
+ isLandscape = true
+ )
+ val dp = getDeviceProfileForGrid("4_by_4")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:true\n" +
+ "\tisLandscape:true\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:true\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 2208.0px (841.1429dp)\n" +
+ "\theightPx: 1840.0px (700.9524dp)\n" +
+ "\tavailableWidthPx: 2208.0px (841.1429dp)\n" +
+ "\tavailableHeightPx: 1730.0px (659.0476dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 110.0px (41.904762dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.2\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 4\n" +
+ "\tinv.numColumns: 4\n" +
+ "\tinv.numSearchContainerColumns: 4\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+ "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tgetCellSize().x: 270.0px (102.85714dp)\n" +
+ "\tgetCellSize().y: 342.0px (130.28572dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+ "\ticonSizePx: 141.0px (53.714287dp)\n" +
+ "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+ "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+ "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 110.0px (41.904762dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 1.0\n" +
+ "\tallAppsShiftRange: 1730.0px (659.0476dp)\n" +
+ "\tallAppsTopPadding: 110.0px (41.904762dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+ "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 8\n" +
+ "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 183.0px (69.71429dp)\n" +
+ "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+ "\tinv.hotseatColumnSpan: 4\n" +
+ "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+ "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 116.0px (44.190475dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 113.0px (43.04762dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 113.0px (43.04762dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.top: 30.0px (11.428572dp)\n" +
+ "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 478.0px (182.09525dp)\n" +
+ "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)\n" +
+ "\tgetCellLayoutHeight(): 1370.0px (521.9048dp)\n" +
+ "\tgetCellLayoutWidth(): 1083.0px (412.57144dp)\n"
+ )
+ }
+
+ @Test
+ fun twoPanelPortrait3Button() {
+ initializeVarsForTwoPanel(
+ deviceSpecs["twopanel-tablet"]!!,
+ deviceSpecs["twopanel-phone"]!!,
+ isGestureMode = false
+ )
+ val dp = getDeviceProfileForGrid("4_by_4")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:false\n" +
+ "\tisLandscape:false\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:true\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 1840.0px (700.9524dp)\n" +
+ "\theightPx: 2208.0px (841.1429dp)\n" +
+ "\tavailableWidthPx: 1840.0px (700.9524dp)\n" +
+ "\tavailableHeightPx: 2075.0px (790.4762dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 133.0px (50.666668dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.2\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 4\n" +
+ "\tinv.numColumns: 4\n" +
+ "\tinv.numSearchContainerColumns: 4\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+ "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tgetCellSize().x: 224.0px (85.333336dp)\n" +
+ "\tgetCellSize().y: 430.0px (163.80952dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+ "\ticonSizePx: 141.0px (53.714287dp)\n" +
+ "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+ "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+ "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 133.0px (50.666668dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 1.0\n" +
+ "\tallAppsShiftRange: 1826.0px (695.619dp)\n" +
+ "\tallAppsTopPadding: 382.0px (145.5238dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+ "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 8\n" +
+ "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 1.0px (0.3809524dp)\n" +
+ "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+ "\tinv.hotseatColumnSpan: 4\n" +
+ "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+ "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 171.0px (65.14286dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 98.0px (37.333332dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 98.0px (37.333332dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.top: 24.0px (9.142858dp)\n" +
+ "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 829.0px (315.8095dp)\n" +
+ "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 168.0px (64.0dp)\n" +
+ "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 490.0px (186.66667dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1770.0px (674.2857dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.7437536px (0.2833347dp)\n" +
+ "\tgetCellLayoutHeight(): 1721.0px (655.619dp)\n" +
+ "\tgetCellLayoutWidth(): 899.0px (342.4762dp)\n"
+ )
+ }
+
+ @Test
+ fun twoPanelPortrait() {
+ initializeVarsForTwoPanel(deviceSpecs["twopanel-tablet"]!!, deviceSpecs["twopanel-phone"]!!)
+ val dp = getDeviceProfileForGrid("4_by_4")
+ dp.isTaskbarPresentInApps = true
+
+ assertThat(dump(dp))
+ .isEqualTo(
+ "DeviceProfile:\n" +
+ "\t1 dp = 2.625 px\n" +
+ "\tisTablet:true\n" +
+ "\tisPhone:false\n" +
+ "\ttransposeLayoutWithOrientation:false\n" +
+ "\tisGestureMode:true\n" +
+ "\tisLandscape:false\n" +
+ "\tisMultiWindowMode:false\n" +
+ "\tisTwoPanels:true\n" +
+ "\twindowX: 0.0px (0.0dp)\n" +
+ "\twindowY: 0.0px (0.0dp)\n" +
+ "\twidthPx: 1840.0px (700.9524dp)\n" +
+ "\theightPx: 2208.0px (841.1429dp)\n" +
+ "\tavailableWidthPx: 1840.0px (700.9524dp)\n" +
+ "\tavailableHeightPx: 2075.0px (790.4762dp)\n" +
+ "\tmInsets.left: 0.0px (0.0dp)\n" +
+ "\tmInsets.top: 133.0px (50.666668dp)\n" +
+ "\tmInsets.right: 0.0px (0.0dp)\n" +
+ "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+ "\taspectRatio:1.2\n" +
+ "\tisScalableGrid:false\n" +
+ "\tinv.numRows: 4\n" +
+ "\tinv.numColumns: 4\n" +
+ "\tinv.numSearchContainerColumns: 4\n" +
+ "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+ "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+ "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+ "\tgetCellSize().x: 224.0px (85.333336dp)\n" +
+ "\tgetCellSize().y: 430.0px (163.80952dp)\n" +
+ "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+ "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+ "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+ "\ticonSizePx: 141.0px (53.714287dp)\n" +
+ "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+ "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+ "\tinv.numFolderRows: 3\n" +
+ "\tinv.numFolderColumns: 4\n" +
+ "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+ "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+ "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+ "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+ "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+ "\tbottomSheetTopPadding: 133.0px (50.666668dp)\n" +
+ "\tbottomSheetOpenDuration: 500\n" +
+ "\tbottomSheetCloseDuration: 500\n" +
+ "\tbottomSheetWorkspaceScale: 0.97\n" +
+ "\tbottomSheetDepth: 1.0\n" +
+ "\tallAppsShiftRange: 1826.0px (695.619dp)\n" +
+ "\tallAppsTopPadding: 382.0px (145.5238dp)\n" +
+ "\tallAppsOpenDuration: 500\n" +
+ "\tallAppsCloseDuration: 500\n" +
+ "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+ "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+ "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+ "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+ "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+ "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+ "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+ "\tnumShownAllAppsColumns: 8\n" +
+ "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+ "\tallAppsLeftRightMargin: 1.0px (0.3809524dp)\n" +
+ "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+ "\tinv.hotseatColumnSpan: 4\n" +
+ "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+ "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+ "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+ "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+ "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+ "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+ "\tspringLoadedHotseatBarTopMarginPx: 171.0px (65.14286dp)\n" +
+ "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+ "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+ "\tgetHotseatLayoutPadding(context).left: 98.0px (37.333332dp)\n" +
+ "\tgetHotseatLayoutPadding(context).right: 98.0px (37.333332dp)\n" +
+ "\tnumShownHotseatIcons: 6\n" +
+ "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+ "\tisQsbInline: false\n" +
+ "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+ "\tisTaskbarPresent:false\n" +
+ "\tisTaskbarPresentInApps:true\n" +
+ "\ttaskbarSize: 0.0px (0.0dp)\n" +
+ "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.top: 24.0px (9.142858dp)\n" +
+ "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+ "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+ "\ticonScale: 1.0px (0.3809524dp)\n" +
+ "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+ "\textraSpace: 829.0px (315.8095dp)\n" +
+ "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+ "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+ "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+ "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+ "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+ "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+ "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+ "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+ "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+ "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+ "\tdropTargetBarTopMarginPx: 168.0px (64.0dp)\n" +
+ "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+ "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkTop(): 490.0px (186.66667dp)\n" +
+ "\tgetCellLayoutSpringLoadShrunkBottom(): 1770.0px (674.2857dp)\n" +
+ "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+ "\tgetWorkspaceSpringLoadScale(): 0.7437536px (0.2833347dp)\n" +
+ "\tgetCellLayoutHeight(): 1721.0px (655.619dp)\n" +
+ "\tgetCellLayoutWidth(): 899.0px (342.4762dp)\n"
+ )
+ }
+
+ private fun getDeviceProfileForGrid(gridName: String): DeviceProfile {
+ return InvariantDeviceProfile(context, gridName).getDeviceProfile(context)
+ }
+
+ private fun dump(dp: DeviceProfile): String {
+ val stringWriter = StringWriter()
+ val printWriter = PrintWriter(stringWriter)
+ dp.dump(context, "", printWriter)
+ printWriter.flush()
+ return stringWriter.toString()
+ }
+}
diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
index 951f5f8..2a27487 100644
--- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
@@ -18,7 +18,7 @@
import android.graphics.Rect
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.launcher3.DeviceProfileBaseTest
+import com.android.launcher3.FakeInvariantDeviceProfileTest
import com.android.launcher3.util.WindowBounds
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -26,7 +26,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
+class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() {
/**
* This is a case when after setting the hotseat, the space needs to be recalculated but it
diff --git a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
index 082e243..7e9d9da 100644
--- a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
+++ b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
@@ -21,7 +21,6 @@
import static com.google.common.truth.Truth.assertThat;
-import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
import android.os.SystemClock;
@@ -34,10 +33,8 @@
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.ui.AbstractLauncherUiTest;
-import com.android.launcher3.util.LauncherModelHelper;
import org.junit.After;
import org.junit.Ignore;
@@ -277,11 +274,6 @@
}
private void setDragNDropFlag(Boolean status) {
- Context context = new LauncherModelHelper().sandboxContext;
- context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit()
- .putBoolean(FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.key, status)
- .commit();
- FeatureFlags.initialize(context);
startSecondaryDisplayActivity();
}
}
diff --git a/tests/src/com/android/launcher3/settings/SettingsActivityTest.java b/tests/src/com/android/launcher3/settings/SettingsActivityTest.java
index 1c205f0..837973f 100644
--- a/tests/src/com/android/launcher3/settings/SettingsActivityTest.java
+++ b/tests/src/com/android/launcher3/settings/SettingsActivityTest.java
@@ -50,6 +50,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.launcher3.R;
+import com.android.launcher3.uioverrides.flags.DeveloperOptionsFragment;
import com.android.systemui.shared.plugins.PluginPrefs;
import org.junit.After;
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 401c25a4..19b8b0c 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -51,11 +51,13 @@
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TISBindRule;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.WidgetsRecyclerView;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,6 +73,9 @@
private static final String STORE_APP_NAME = "Play Store";
private static final String GMAIL_APP_NAME = "Gmail";
+ @Rule
+ public TISBindRule mTISBindRule = new TISBindRule();
+
@Before
public void setUp() throws Exception {
super.setUp();
@@ -214,7 +219,7 @@
false /* tapRight */);
}
- @IwTest(focusArea="launcher")
+ @IwTest(focusArea = "launcher")
@Test
@ScreenRecord // b/202433017
public void testWorkspace() throws Exception {
@@ -341,7 +346,7 @@
}
}
- @IwTest(focusArea="launcher")
+ @IwTest(focusArea = "launcher")
@Test
@PortraitLandscape
@ScreenRecord // b/256898879
@@ -610,16 +615,16 @@
/**
* @return List of workspace grid coordinates. Those are not pixels. See {@link
- * Workspace#getIconGridDimensions()}
+ * Workspace#getIconGridDimensions()}
*/
private Point[] getCornersAndCenterPositions() {
final Point dimensions = mLauncher.getWorkspace().getIconGridDimensions();
- return new Point[] {
- new Point(0, 1),
- new Point(0, dimensions.y - 2),
- new Point(dimensions.x - 1, 1),
- new Point(dimensions.x - 1, dimensions.y - 2),
- new Point(dimensions.x / 2, dimensions.y / 2)
+ return new Point[]{
+ new Point(0, 1),
+ new Point(0, dimensions.y - 2),
+ new Point(dimensions.x - 1, 1),
+ new Point(dimensions.x - 1, dimensions.y - 2),
+ new Point(dimensions.x / 2, dimensions.y / 2)
};
}
diff --git a/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt b/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
index 4303bfb..c9c9616 100644
--- a/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
+++ b/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
@@ -101,15 +101,18 @@
/**
* Helper function for creating and using a single-use ArgumentCaptor in kotlin.
+ *
* ```
* val captor = argumentCaptor<Foo>()
* verify(...).someMethod(captor.capture())
* val captured = captor.value
* ```
+ *
* becomes:
* ```
* val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) }
* ```
+ *
* NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException.
*/
inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index fa4c519..545b645 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -510,7 +510,7 @@
UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
- SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
+ SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE, LockedUserState.INSTANCE,
ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
mPm = spy(getBaseContext().getPackageManager());
mDbDir = new File(getCacheDir(), UUID.randomUUID().toString());
diff --git a/tests/src/com/android/launcher3/util/TestResourceHelper.kt b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
new file mode 100644
index 0000000..fb03fe1
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.util
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.util.AttributeSet
+import com.android.launcher3.R
+import com.android.launcher3.tests.R as TestR
+import kotlin.IntArray
+
+class TestResourceHelper(private val context: Context, private val specsFileId: Int) :
+ ResourceHelper(context, specsFileId) {
+ override fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray {
+ var clone = styleId.clone()
+ if (styleId == R.styleable.SpecSize) clone = TestR.styleable.SpecSize
+ else if (styleId == R.styleable.WorkspaceSpec) clone = TestR.styleable.WorkspaceSpec
+ return context.obtainStyledAttributes(attrs, clone)
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/TISBindRule.java b/tests/src/com/android/launcher3/util/rule/TISBindRule.java
new file mode 100644
index 0000000..3ec4a29
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/TISBindRule.java
@@ -0,0 +1,81 @@
+/*
+ * 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.util.rule;
+
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class TISBindRule implements TestRule {
+ public static String TAG = "TISBindRule";
+ public static String INTENT_FILTER = "android.intent.action.QUICKSTEP_SERVICE";
+ public static String TIS_PERMISSIONS = "android.permission.STATUS_BAR_SERVICE";
+
+ private String getLauncherPackageName(Context context) {
+ return ComponentName.unflattenFromString(context.getString(
+ com.android.internal.R.string.config_recentsComponentName)).getPackageName();
+ }
+
+ private ServiceConnection createConnection() {
+ return new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ Log.d(TAG, "Connected to TouchInteractionService");
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ Log.d(TAG, "Disconnected from TouchInteractionService");
+ }
+ };
+ }
+
+ @NonNull
+ @Override
+ public Statement apply(@NonNull Statement base, @NonNull Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ final ServiceConnection connection = createConnection();
+ UiAutomation uiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity(TIS_PERMISSIONS);
+ Intent launchIntent = new Intent(INTENT_FILTER);
+ launchIntent.setPackage(getLauncherPackageName(context));
+ context.bindService(launchIntent, connection, Context.BIND_AUTO_CREATE);
+ uiAutomation.dropShellPermissionIdentity();
+ try {
+ base.evaluate();
+ } finally {
+ context.unbindService(connection);
+ }
+ }
+ };
+ }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
deleted file mode 100644
index b480a4c..0000000
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.picker;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
-import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.UserHandle;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.picker.WidgetsListAdapter.WidgetListBaseRowEntryComparator;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class WidgetsDiffReporterTest {
- private static final String TEST_PACKAGE_PREFIX = "com.android.test";
- private static final WidgetListBaseRowEntryComparator COMPARATOR =
- new WidgetListBaseRowEntryComparator();
-
- @Mock private IconCache mIconCache;
- @Mock private RecyclerView.Adapter mAdapter;
-
- private InvariantDeviceProfile mTestProfile;
- private WidgetsDiffReporter mWidgetsDiffReporter;
- private Context mContext;
- private WidgetsListHeaderEntry mHeaderA;
- private WidgetsListHeaderEntry mHeaderB;
- private WidgetsListHeaderEntry mHeaderC;
- private WidgetsListHeaderEntry mHeaderD;
- private WidgetsListHeaderEntry mHeaderE;
- private WidgetsListContentEntry mContentC;
- private WidgetsListContentEntry mContentE;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mTestProfile = new InvariantDeviceProfile();
- mTestProfile.numRows = 5;
- mTestProfile.numColumns = 5;
-
- doAnswer(invocation -> ((ComponentWithLabel) invocation.getArgument(0))
- .getComponent().getPackageName())
- .when(mIconCache).getTitleNoCache(any());
-
- mContext = getApplicationContext();
- mWidgetsDiffReporter = new WidgetsDiffReporter(mIconCache, mAdapter);
- mHeaderA = createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "A",
- /* appName= */ "A", /* numOfWidgets= */ 3);
- mHeaderB = createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "B",
- /* appName= */ "B", /* numOfWidgets= */ 3);
- mHeaderC = createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "C",
- /* appName= */ "C", /* numOfWidgets= */ 3);
- mContentC = createWidgetsContentEntry(TEST_PACKAGE_PREFIX + "C",
- /* appName= */ "C", /* numOfWidgets= */ 3);
- mHeaderD = createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "D",
- /* appName= */ "D", /* numOfWidgets= */ 3);
- mHeaderE = createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "E",
- /* appName= */ "E", /* numOfWidgets= */ 3);
- mContentE = createWidgetsContentEntry(TEST_PACKAGE_PREFIX + "E",
- /* appName= */ "E", /* numOfWidgets= */ 3);
- }
-
- @Test
- public void listNotChanged_shouldNotInvokeAnyCallbacks() {
- // GIVEN the current list has app headers [A, B, C].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>(
- List.of(mHeaderA, mHeaderB, mHeaderC));
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, currentList, COMPARATOR);
-
- // THEN there is no adaptor callback.
- verifyZeroInteractions(mAdapter);
- // THEN the current list contains the same entries.
- assertThat(currentList).containsExactly(mHeaderA, mHeaderB, mHeaderC);
- }
-
- @Test
- public void headersOnly_emptyListToNonEmpty_shouldInvokeNotifyDataSetChanged() {
- // GIVEN the current list has app headers [A, B, C].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>();
-
- List<WidgetsListBaseEntry> newList = List.of(
- createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "A", "A", 3),
- createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "B", "B", 3),
- createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "C", "C", 3));
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, newList, COMPARATOR);
-
- // THEN notifyDataSetChanged is called
- verify(mAdapter).notifyDataSetChanged();
- // THEN the current list contains all elements from the new list.
- assertThat(currentList).containsExactlyElementsIn(newList);
- }
-
- @Test
- public void headersOnly_nonEmptyToEmptyList_shouldInvokeNotifyDataSetChanged() {
- // GIVEN the current list has app headers [A, B, C].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>(
- List.of(mHeaderA, mHeaderB, mHeaderC));
- // GIVEN the new list is empty.
- List<WidgetsListBaseEntry> newList = List.of();
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, newList, COMPARATOR);
-
- // THEN notifyDataSetChanged is called.
- verify(mAdapter).notifyDataSetChanged();
- // THEN the current list isEmpty.
- assertThat(currentList).isEmpty();
- }
-
- @Test
- public void headersOnly_itemAddedAndRemovedInTheNewList_shouldInvokeCorrectCallbacks() {
- // GIVEN the current list has app headers [A, B, D].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>(
- List.of(mHeaderA, mHeaderB, mHeaderD));
- // GIVEN the new list has app headers [A, C, E].
- List<WidgetsListBaseEntry> newList = List.of(mHeaderA, mHeaderC, mHeaderE);
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, newList, COMPARATOR);
-
- // THEN "B" is removed from position 1.
- verify(mAdapter).notifyItemRemoved(/* position= */ 1);
- // THEN "D" is removed from position 2.
- verify(mAdapter).notifyItemRemoved(/* position= */ 2);
- // THEN "C" is inserted at position 1.
- verify(mAdapter).notifyItemInserted(/* position= */ 1);
- // THEN "E" is inserted at position 2.
- verify(mAdapter).notifyItemInserted(/* position= */ 2);
- // THEN the current list contains all elements from the new list.
- assertThat(currentList).containsExactlyElementsIn(newList);
- }
-
- @Test
- public void headersContentsMix_itemAddedAndRemovedInTheNewList_shouldInvokeCorrectCallbacks() {
- // GIVEN the current list has app headers [A, B, E content].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>(
- List.of(mHeaderA, mHeaderB, mContentE));
- // GIVEN the new list has app headers [A, C content, D].
- List<WidgetsListBaseEntry> newList = List.of(mHeaderA, mContentC, mHeaderD);
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, newList, COMPARATOR);
-
- // THEN "B" is removed from position 1.
- verify(mAdapter).notifyItemRemoved(/* position= */ 1);
- // THEN "C content" is inserted at position 1.
- verify(mAdapter).notifyItemInserted(/* position= */ 1);
- // THEN "D" is inserted at position 2.
- verify(mAdapter).notifyItemInserted(/* position= */ 2);
- // THEN "E content" is removed from position 3.
- verify(mAdapter).notifyItemRemoved(/* position= */ 3);
- // THEN the current list contains all elements from the new list.
- assertThat(currentList).containsExactlyElementsIn(newList);
- }
-
- @Test
- public void headersContentsMix_userInteractWithHeader_shouldInvokeCorrectCallbacks() {
- // GIVEN the current list has app headers [A, B, E content].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>(
- List.of(mHeaderA, mHeaderB, mContentE));
- // GIVEN the new list has app headers [A, B, E content] and the user has interacted with B.
- List<WidgetsListBaseEntry> newList =
- List.of(mHeaderA, mHeaderB.withWidgetListShown(), mContentE);
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, newList, COMPARATOR);
-
- // THEN notify "B" has been changed.
- verify(mAdapter).notifyItemChanged(/* position= */ 1);
- // THEN the current list contains all elements from the new list.
- assertThat(currentList).containsExactlyElementsIn(newList);
- }
-
- @Test
- public void headersContentsMix_headerWidgetsModified_shouldInvokeCorrectCallbacks() {
- // GIVEN the current list has app headers [A, B, E content].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>(
- List.of(mHeaderA, mHeaderB, mContentE));
- // GIVEN the new list has one of the headers widgets list modified.
- List<WidgetsListBaseEntry> newList = List.of(
- new WidgetsListHeaderEntry(
- mHeaderA.mPkgItem, mHeaderA.mTitleSectionName,
- mHeaderA.mWidgets.subList(0, 1)),
- mHeaderB, mContentE);
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, newList, COMPARATOR);
-
- // THEN notify "A" has been changed.
- verify(mAdapter).notifyItemChanged(/* position= */ 0);
- // THEN the current list contains all elements from the new list.
- assertThat(currentList).containsExactlyElementsIn(newList);
- }
-
- @Test
- public void headersContentsMix_contentMaxSpanSizeModified_shouldInvokeCorrectCallbacks() {
- // GIVEN the current list has app headers [A, B, E content].
- ArrayList<WidgetsListBaseEntry> currentList = new ArrayList<>(
- List.of(mHeaderA, mHeaderB, mContentE));
- // GIVEN the new list has max span size in "E content" modified.
- List<WidgetsListBaseEntry> newList = List.of(
- mHeaderA,
- mHeaderB,
- new WidgetsListContentEntry(
- mContentE.mPkgItem,
- mContentE.mTitleSectionName,
- mContentE.mWidgets,
- mContentE.getMaxSpanSizeInCells() + 1));
-
- // WHEN computing the list difference.
- mWidgetsDiffReporter.process(currentList, newList, COMPARATOR);
-
- // THEN notify "E content" has been changed.
- verify(mAdapter).notifyItemChanged(/* position= */ 2);
- // THEN the current list contains all elements from the new list.
- assertThat(currentList).containsExactlyElementsIn(newList);
- }
-
-
- private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
- int numOfWidgets) {
- List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
- PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
- widgetItems.get(0).user);
-
- return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
- }
-
- private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
- int numOfWidgets) {
- List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
- PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
- widgetItems.get(0).user);
-
- return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
- }
-
- private PackageItemInfo createPackageItemInfo(String packageName, String appName,
- UserHandle userHandle) {
- PackageItemInfo pInfo = new PackageItemInfo(packageName, userHandle);
- pInfo.title = appName;
- pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
- return pInfo;
- }
-
- private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
- ArrayList<WidgetItem> widgetItems = new ArrayList<>();
- for (int i = 0; i < numOfWidgets; i++) {
- ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
- AppWidgetProviderInfo widgetInfo = createAppWidgetProviderInfo(cn);
-
- WidgetItem widgetItem = new WidgetItem(
- LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
- mTestProfile, mIconCache);
- widgetItems.add(widgetItem);
- }
- return widgetItems;
- }
-}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
deleted file mode 100644
index 4e0bdda..0000000
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.picker;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.Process;
-import android.os.UserHandle;
-import android.view.LayoutInflater;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.ActivityContextWrapper;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.WidgetUtils;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit tests for WidgetsListAdapter
- * Note that all indices matching are shifted by 1 to account for the empty space at the start.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class WidgetsListAdapterTest {
- private static final String TEST_PACKAGE_PLACEHOLDER = "com.google.test";
-
- @Mock private LayoutInflater mMockLayoutInflater;
- @Mock private RecyclerView.AdapterDataObserver mListener;
- @Mock private IconCache mIconCache;
-
- private WidgetsListAdapter mAdapter;
- private InvariantDeviceProfile mTestProfile;
- private UserHandle mUserHandle;
- private Context mContext;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mContext = new ActivityContextWrapper(getApplicationContext());
- mTestProfile = new InvariantDeviceProfile();
- mTestProfile.numRows = 5;
- mTestProfile.numColumns = 5;
- mUserHandle = Process.myUserHandle();
- mAdapter = new WidgetsListAdapter(mContext, mMockLayoutInflater,
- mIconCache, () -> 0, null, null);
- mAdapter.registerAdapterDataObserver(mListener);
-
- doAnswer(invocation -> ((ComponentWithLabel) invocation.getArgument(0))
- .getComponent().getPackageName())
- .when(mIconCache).getTitleNoCache(any());
- }
-
- @Test
- public void setWidgets_shouldNotifyDataSetChanged() {
- mAdapter.setWidgets(generateSampleMap(1));
-
- verify(mListener).onChanged();
- }
-
- @Test
- public void setWidgets_withItemInserted_shouldNotifyItemInserted() {
- mAdapter.setWidgets(generateSampleMap(1));
- mAdapter.setWidgets(generateSampleMap(2));
-
- verify(mListener).onItemRangeInserted(eq(2), eq(1));
- }
-
- @Test
- public void setWidgets_withItemRemoved_shouldNotifyItemRemoved() {
- mAdapter.setWidgets(generateSampleMap(2));
- mAdapter.setWidgets(generateSampleMap(1));
-
- verify(mListener).onItemRangeRemoved(eq(2), eq(1));
- }
-
- @Test
- public void setWidgets_appIconChanged_shouldNotifyItemChanged() {
- mAdapter.setWidgets(generateSampleMap(1));
- mAdapter.setWidgets(generateSampleMap(1));
-
- verify(mListener).onItemRangeChanged(eq(1), eq(1), isNull());
- }
-
- @Test
- public void headerClick_expanded_shouldNotifyItemChange() {
- // GIVEN a list of widgets entries:
- // [com.google.test0, com.google.test0 content,
- // com.google.test1, com.google.test1 content,
- // com.google.test2, com.google.test2 content]
- // The visible widgets entries: [com.google.test0, com.google.test1, com.google.test2].
- mAdapter.setWidgets(generateSampleMap(3));
-
- // WHEN com.google.test.1 header is expanded.
- mAdapter.onHeaderClicked(/* showWidgets= */ true,
- new PackageUserKey(TEST_PACKAGE_PLACEHOLDER + 1, mUserHandle));
-
- // THEN the visible entries list becomes:
- // [com.google.test0, com.google.test1, com.google.test1 content, com.google.test2]
- // com.google.test.1 content is inserted into position 2.
- verify(mListener).onItemRangeInserted(eq(3), eq(1));
- }
-
- @Test
- public void setWidgets_expandedApp_moreWidgets_shouldNotifyItemChangedWithWidgetItemInfoDiff() {
- // GIVEN the adapter was first populated with com.google.test0 & com.google.test1. Each app
- // has one widget.
- ArrayList<WidgetsListBaseEntry> allEntries = generateSampleMap(2);
- mAdapter.setWidgets(allEntries);
- // GIVEN test com.google.test1 is expanded.
- // Visible entries in the adapter are:
- // [com.google.test0, com.google.test1, com.google.test1 content]
- mAdapter.onHeaderClicked(/* showWidgets= */ true,
- new PackageUserKey(TEST_PACKAGE_PLACEHOLDER + 1, mUserHandle));
- Mockito.reset(mListener);
-
- // WHEN the adapter is updated with the same list of apps but com.google.test1 has 2 widgets
- // now.
- WidgetsListContentEntry testPackage1ContentEntry =
- (WidgetsListContentEntry) allEntries.get(3);
- WidgetItem widgetItem = testPackage1ContentEntry.mWidgets.get(0);
- WidgetsListContentEntry newTestPackage1ContentEntry = new WidgetsListContentEntry(
- testPackage1ContentEntry.mPkgItem,
- testPackage1ContentEntry.mTitleSectionName, List.of(widgetItem, widgetItem));
- allEntries.set(3, newTestPackage1ContentEntry);
- mAdapter.setWidgets(allEntries);
-
- // THEN the onItemRangeChanged is invoked for "com.google.test1 content" at index 2.
- verify(mListener).onItemRangeChanged(eq(3), eq(1), isNull());
- }
-
- @Test
- public void setWidgets_hodgepodge_shouldInvokeExpectedDataObserverCallbacks() {
- // GIVEN a widgets entry list:
- // Index: 0| 1 | 2| 3 | 4| 5 | 6| 7 | 8| 9 |
- // [A, A content, B, B content, C, C content, D, D content, E, E content]
- List<WidgetsListBaseEntry> allAppsWithWidgets = generateSampleMap(5);
- // GIVEN the current widgets list consist of [A, A content, B, B content, E, E content].
- // GIVEN the visible widgets list consist of [A, B, E]
- List<WidgetsListBaseEntry> currentList = List.of(
- // A & A content
- allAppsWithWidgets.get(0), allAppsWithWidgets.get(1),
- // B & B content
- allAppsWithWidgets.get(2), allAppsWithWidgets.get(3),
- // E & E content
- allAppsWithWidgets.get(8), allAppsWithWidgets.get(9));
- mAdapter.setWidgets(currentList);
-
- // WHEN the widgets list is updated to [A, A content, C, C content, D, D content].
- // WHEN the visible widgets list is updated to [A, C, D].
- List<WidgetsListBaseEntry> newList = List.of(
- // A & A content
- allAppsWithWidgets.get(0), allAppsWithWidgets.get(1),
- // C & C content
- allAppsWithWidgets.get(4), allAppsWithWidgets.get(5),
- // D & D content
- allAppsWithWidgets.get(6), allAppsWithWidgets.get(7));
- mAdapter.setWidgets(newList);
-
- // Account for 1st items as empty space
- // Computation logic | [Intermediate list during computation]
- // THEN B <> C < 0, removed B from index 1 | [A, E]
- verify(mListener).onItemRangeRemoved(/* positionStart= */ 2, /* itemCount= */ 1);
- // THEN E <> C > 0, C inserted to index 1 | [A, C, E]
- verify(mListener).onItemRangeInserted(/* positionStart= */ 2, /* itemCount= */ 1);
- // THEN E <> D > 0, D inserted to index 2 | [A, C, D, E]
- verify(mListener).onItemRangeInserted(/* positionStart= */ 3, /* itemCount= */ 1);
- // THEN E <> null = -1, E deleted from index 3 | [A, C, D]
- verify(mListener).onItemRangeRemoved(/* positionStart= */ 4, /* itemCount= */ 1);
- }
-
- @Test
- public void setWidgetsOnSearch_expandedApp_shouldResetExpandedApp() {
- // GIVEN a list of widgets entries:
- // [Empty item
- // com.google.test0,
- // com.google.test0 content,
- // com.google.test1,
- // com.google.test1 content,
- // com.google.test2,
- // com.google.test2 content]
- // The visible widgets entries:
- // [Empty item,
- // com.google.test0,
- // com.google.test1,
- // com.google.test2].
- ArrayList<WidgetsListBaseEntry> allEntries = generateSampleMap(3);
- mAdapter.setWidgetsOnSearch(allEntries);
- // GIVEN com.google.test.1 header is expanded. The visible entries list becomes:
- // [Empty item, com.google.test0, com.google.test1, com.google.test1 content,
- // com.google.test2]
- mAdapter.onHeaderClicked(/* showWidgets= */ true,
- new PackageUserKey(TEST_PACKAGE_PLACEHOLDER + 1, mUserHandle));
- Mockito.reset(mListener);
-
- // WHEN same widget entries are set again.
- mAdapter.setWidgetsOnSearch(allEntries);
-
- // THEN expanded app is reset and the visible entries list becomes:
- // [Empty item, com.google.test0, com.google.test1, com.google.test2]
- verify(mListener).onItemRangeChanged(eq(2), eq(1), isNull());
- verify(mListener).onItemRangeRemoved(/* positionStart= */ 3, /* itemCount= */ 1);
- }
-
- /**
- * Generates a list of sample widget entries.
- *
- * <p>Each sample app has 1 widget only. An app is represented by 2 entries,
- * {@link WidgetsListHeaderEntry} & {@link WidgetsListContentEntry}. Only
- * {@link WidgetsListHeaderEntry} is always visible in the {@link WidgetsListAdapter}.
- * {@link WidgetsListContentEntry} is only shown upon clicking the corresponding app's
- * {@link WidgetsListHeaderEntry}. Only at most one {@link WidgetsListContentEntry} is shown at
- * a time.
- *
- * @param num the number of apps that have widgets.
- */
- private ArrayList<WidgetsListBaseEntry> generateSampleMap(int num) {
- ArrayList<WidgetsListBaseEntry> result = new ArrayList<>();
- if (num <= 0) return result;
-
- for (int i = 0; i < num; i++) {
- String packageName = TEST_PACKAGE_PLACEHOLDER + i;
-
- List<WidgetItem> widgetItems = generateWidgetItems(packageName, /* numOfWidgets= */ 1);
-
- PackageItemInfo pInfo = new PackageItemInfo(packageName, widgetItems.get(0).user);
- pInfo.title = pInfo.packageName;
- pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
-
- result.add(new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems));
- result.add(new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems));
- }
-
- return result;
- }
-
- private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
- ArrayList<WidgetItem> widgetItems = new ArrayList<>();
- for (int i = 0; i < numOfWidgets; i++) {
- ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
- AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
-
- widgetItems.add(new WidgetItem(
- LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
- mTestProfile, mIconCache));
- }
- return widgetItems;
- }
-}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 211318c..76492ba 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -91,7 +91,7 @@
mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
LayoutInflater.from(mContext),
mOnHeaderClickListener,
- new WidgetsListDrawableFactory(mContext));
+ false);
}
@Test
@@ -134,7 +134,7 @@
appInfo.title = appName;
appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
- return new WidgetsListHeaderEntry(appInfo,
+ return WidgetsListHeaderEntry.create(appInfo,
/* titleSectionName= */ "",
generateWidgetItems(packageName, numOfWidgets));
}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
deleted file mode 100644
index 66c2f36..0000000
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.picker;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-
-import static java.util.Collections.EMPTY_LIST;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.UserHandle;
-import android.view.LayoutInflater;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.ActivityContextWrapper;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.WidgetUtils;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class WidgetsListSearchHeaderViewHolderBinderTest {
- private static final String TEST_PACKAGE = "com.google.test";
- private static final String APP_NAME = "Test app";
-
- private Context mContext;
- private WidgetsListSearchHeaderViewHolderBinder mViewHolderBinder;
- private InvariantDeviceProfile mTestProfile;
-
- @Mock
- private IconCache mIconCache;
- @Mock
- private OnHeaderClickListener mOnHeaderClickListener;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = new ActivityContextWrapper(getApplicationContext());
- mTestProfile = new InvariantDeviceProfile();
- mTestProfile.numRows = 5;
- mTestProfile.numColumns = 5;
-
- doAnswer(invocation -> {
- ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
- return componentWithLabel.getComponent().getShortClassName();
- }).when(mIconCache).getTitleNoCache(any());
- mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
- LayoutInflater.from(mContext),
- mOnHeaderClickListener,
- new WidgetsListDrawableFactory(mContext));
- }
-
- @Test
- public void bindViewHolder_appWith3Widgets_shouldShowTheCorrectAppNameAndSubtitle() {
- WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
- new FrameLayout(mContext));
- WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
- APP_NAME,
- TEST_PACKAGE,
- /* numOfWidgets= */ 3);
- mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
-
- TextView appTitle = widgetsListHeader.findViewById(R.id.app_title);
- TextView appSubtitle = widgetsListHeader.findViewById(R.id.app_subtitle);
- assertThat(appTitle.getText()).isEqualTo(APP_NAME);
- assertThat(appSubtitle.getText())
- .isEqualTo(".SampleWidget0, .SampleWidget1, .SampleWidget2");
- }
-
- @Test
- public void bindViewHolder_shouldAttachOnHeaderClickListener() {
- WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
- new FrameLayout(mContext));
- WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
- APP_NAME,
- TEST_PACKAGE,
- /* numOfWidgets= */ 3);
-
- mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
- widgetsListHeader.callOnClick();
-
- verify(mOnHeaderClickListener).onHeaderClicked(eq(true),
- eq(PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
- }
-
- private WidgetsListSearchHeaderEntry generateSampleSearchHeader(String appName,
- String packageName, int numOfWidgets) {
- PackageItemInfo appInfo = new PackageItemInfo(packageName, UserHandle.CURRENT);
- appInfo.title = appName;
- appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
-
- return new WidgetsListSearchHeaderEntry(appInfo,
- /* titleSectionName= */ "",
- generateWidgetItems(packageName, numOfWidgets));
- }
-
- private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
- ArrayList<WidgetItem> widgetItems = new ArrayList<>();
- for (int i = 0; i < numOfWidgets; i++) {
- ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
- AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
-
- widgetItems.add(new WidgetItem(
- LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
- mTestProfile, mIconCache));
- }
- return widgetItems;
- }
-}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 7ec4d20..9dc46f1 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -96,8 +96,7 @@
mViewHolderBinder = new WidgetsListTableViewHolderBinder(
LayoutInflater.from(mContext),
mOnIconClickListener,
- mOnLongClickListener,
- new WidgetsListDrawableFactory(mContext));
+ mOnLongClickListener);
}
@Test
diff --git a/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
index d812ab0..0124f73 100644
--- a/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
@@ -50,7 +50,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import org.junit.Before;
import org.junit.Test;
@@ -117,12 +116,12 @@
.getAllWidgets();
assertEquals(List.of(
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets),
mCalendarContentEntry,
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCameraHeaderEntry.mPkgItem,
mCameraHeaderEntry.mTitleSectionName,
mCameraHeaderEntry.mWidgets),
@@ -138,7 +137,7 @@
.getAllWidgets();
assertEquals(List.of(
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
@@ -146,7 +145,7 @@
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCameraHeaderEntry.mPkgItem,
mCameraHeaderEntry.mTitleSectionName,
mCameraHeaderEntry.mWidgets.subList(1, 3)),
@@ -175,7 +174,7 @@
PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
widgetItems.get(0).user);
- return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+ return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
}
private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
diff --git a/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
new file mode 100644
index 0000000..0fd8a54
--- /dev/null
+++ b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.workspace
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.tests.R as TestR
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WorkspaceSpecsTest : AbstractDeviceProfileTest() {
+ override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+
+ @Before
+ fun setup() {
+ initializeVarsForPhone(deviceSpecs["phone"]!!)
+ }
+
+ @Test
+ fun parseValidFile() {
+ val workspaceSpecs =
+ WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
+ assertThat(workspaceSpecs.workspaceHeightSpecList.size).isEqualTo(2)
+ assertThat(workspaceSpecs.workspaceHeightSpecList[0].toString())
+ .isEqualTo(
+ "WorkspaceSpec(" +
+ "maxAvailableSize=1701, " +
+ "specType=HEIGHT, " +
+ "startPadding=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0125, " +
+ "ofRemainderSpace=0.0), " +
+ "endPadding=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.05, " +
+ "ofRemainderSpace=0.0), " +
+ "gutter=SizeSpec(fixedSize=42.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.0), " +
+ "cellSize=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.2)" +
+ ")"
+ )
+ assertThat(workspaceSpecs.workspaceHeightSpecList[1].toString())
+ .isEqualTo(
+ "WorkspaceSpec(" +
+ "maxAvailableSize=26247, " +
+ "specType=HEIGHT, " +
+ "startPadding=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0306, " +
+ "ofRemainderSpace=0.0), " +
+ "endPadding=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.068, " +
+ "ofRemainderSpace=0.0), " +
+ "gutter=SizeSpec(fixedSize=42.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.0), " +
+ "cellSize=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.2)" +
+ ")"
+ )
+ assertThat(workspaceSpecs.workspaceWidthSpecList.size).isEqualTo(1)
+ assertThat(workspaceSpecs.workspaceWidthSpecList[0].toString())
+ .isEqualTo(
+ "WorkspaceSpec(" +
+ "maxAvailableSize=26247, " +
+ "specType=WIDTH, " +
+ "startPadding=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.21436226), " +
+ "endPadding=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.21436226), " +
+ "gutter=SizeSpec(fixedSize=0.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.11425509), " +
+ "cellSize=SizeSpec(fixedSize=315.0, " +
+ "ofAvailableSpace=0.0, " +
+ "ofRemainderSpace=0.0)" +
+ ")"
+ )
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_missingTag_throwsError() {
+ WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_1))
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
+ WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_2))
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_valueBiggerThan1_throwsError() {
+ WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_3))
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsQsb.java b/tests/tapl/com/android/launcher3/tapl/AllAppsQsb.java
new file mode 100644
index 0000000..0931cd4
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsQsb.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Operations on AllApp screen qsb.
+ */
+class AllAppsQsb extends Qsb {
+
+ private final UiObject2 mAllAppsContainer;
+
+ AllAppsQsb(LauncherInstrumentation launcher, UiObject2 allAppsContainer) {
+ super(launcher);
+ mAllAppsContainer = allAppsContainer;
+ waitForQsbObject();
+ }
+
+ @Override
+ protected UiObject2 waitForQsbObject() {
+ return mLauncher.waitForObjectInContainer(mAllAppsContainer, "search_container_all_apps");
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index e0c4c19..44de65a 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -109,4 +109,13 @@
}
}
}
+
+ /**
+ * Return the QSB UI object on the AllApps screen.
+ * @return the QSB UI object.
+ */
+ @NonNull
+ public Qsb getQsb() {
+ return new AllAppsQsb(mLauncher, verifyActiveContainer());
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
index c365708..20d09a1 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
@@ -15,69 +15,23 @@
*/
package com.android.launcher3.tapl;
-import androidx.annotation.NonNull;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
/**
- * Operations on home screen qsb.
+ * Operations on Home screen qsb.
*/
-public class HomeQsb {
+class HomeQsb extends Qsb {
- private final LauncherInstrumentation mLauncher;
- private static final String ASSISTANT_APP_PACKAGE = "com.google.android.googlequicksearchbox";
- private static final String ASSISTANT_ICON_RES_ID = "mic_icon";
+ private final UiObject2 mHotSeat;
-
- HomeQsb(LauncherInstrumentation launcher) {
- mLauncher = launcher;
- mLauncher.waitForLauncherObject("search_container_hotseat");
+ HomeQsb(LauncherInstrumentation launcher, UiObject2 hotseat) {
+ super(launcher);
+ mHotSeat = hotseat;
+ waitForQsbObject();
}
- /**
- * Launch assistant app by tapping mic icon on qsb.
- */
- @NonNull
- public LaunchedAppState launchAssistant() {
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to click assistant mic icon button");
- LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- UiObject2 assistantIcon = mLauncher.waitForLauncherObject(ASSISTANT_ICON_RES_ID);
-
- LauncherInstrumentation.log("HomeQsb.launchAssistant before click "
- + assistantIcon.getVisibleCenter() + " in "
- + mLauncher.getVisibleBounds(assistantIcon));
-
- mLauncher.clickLauncherObject(assistantIcon);
-
- try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) {
- // assert Assistant App Launched
- BySelector selector = By.pkg(ASSISTANT_APP_PACKAGE);
- mLauncher.assertTrue(
- "assistant app didn't start: (" + selector + ")",
- mLauncher.getDevice().wait(Until.hasObject(selector),
- LauncherInstrumentation.WAIT_TIME_MS)
- );
- return new LaunchedAppState(mLauncher);
- }
- }
- }
-
- /**
- * Show search result page from tapping qsb.
- */
- public SearchResultFromQsb showSearchResult() {
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to open search result page");
- LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- mLauncher.clickLauncherObject(
- mLauncher.waitForLauncherObject("search_container_hotseat"));
- try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
- "clicked qsb to open search result page")) {
- return new SearchResultFromQsb(mLauncher);
- }
- }
+ @Override
+ protected UiObject2 waitForQsbObject() {
+ return mLauncher.waitForObjectInContainer(mHotSeat, "search_container_hotseat");
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Qsb.java b/tests/tapl/com/android/launcher3/tapl/Qsb.java
new file mode 100644
index 0000000..6bc4f21
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Qsb.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+/**
+ * Operations on qsb from either Home screen or AllApp screen.
+ */
+public abstract class Qsb {
+
+ private static final String ASSISTANT_APP_PACKAGE = "com.google.android.googlequicksearchbox";
+ private static final String ASSISTANT_ICON_RES_ID = "mic_icon";
+ protected final LauncherInstrumentation mLauncher;
+
+ protected Qsb(LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ }
+
+ // Waits for the quick search box.
+ protected abstract UiObject2 waitForQsbObject();
+ /**
+ * Launch assistant app by tapping mic icon on qsb.
+ */
+
+ @NonNull
+ public LaunchedAppState launchAssistant() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to click assistant mic icon button");
+ LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ UiObject2 assistantIcon = mLauncher.waitForLauncherObject(ASSISTANT_ICON_RES_ID);
+
+ LauncherInstrumentation.log("Qsb.launchAssistant before click "
+ + assistantIcon.getVisibleCenter() + " in "
+ + mLauncher.getVisibleBounds(assistantIcon));
+
+ mLauncher.clickLauncherObject(assistantIcon);
+
+ try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) {
+ // assert Assistant App Launched
+ BySelector selector = By.pkg(ASSISTANT_APP_PACKAGE);
+ mLauncher.assertTrue(
+ "assistant app didn't start: (" + selector + ")",
+ mLauncher.getDevice().wait(Until.hasObject(selector),
+ LauncherInstrumentation.WAIT_TIME_MS)
+ );
+ return new LaunchedAppState(mLauncher);
+ }
+ }
+ }
+
+ /**
+ * Show search result page from tapping qsb.
+ */
+ public SearchResultFromQsb showSearchResult() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to open search result page");
+ LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ mLauncher.clickLauncherObject(waitForQsbObject());
+ // wait for the result rendering to complete
+ mLauncher.waitForIdle();
+ try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
+ "clicked qsb to open search result page")) {
+ return new SearchResultFromQsb(mLauncher);
+ }
+ }
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index 80e4116..80176e9 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -23,7 +23,7 @@
import java.util.ArrayList;
/**
- * Operations on search result page opened from home screen qsb.
+ * Operations on search result page opened from qsb.
*/
public class SearchResultFromQsb {
// The input resource id in the search box.
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 473cfb9..1939dc6 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -67,6 +67,7 @@
"Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_W"
+ ".*?metaState=META_CTRL_ON");
static final Pattern LONG_CLICK_EVENT = Pattern.compile("onWorkspaceItemLongClick");
+ public static final int MAX_WORKSPACE_DRAG_TRIES = 100;
private final UiObject2 mHotseat;
@@ -118,10 +119,11 @@
*
* The qsb must already be visible when calling this method.
*/
- public HomeQsb getQsb() {
+ @NonNull
+ public Qsb getQsb() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get the home qsb")) {
- return new HomeQsb(mLauncher);
+ return new HomeQsb(mLauncher, mHotseat);
}
}
@@ -430,6 +432,12 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ /** Returns the index of the current page */
+ static int geCurrentPage(LauncherInstrumentation launcher) {
+ return launcher.getTestInfo(TestProtocol.REQUEST_WORKSPACE_CURRENT_PAGE_INDEX).getInt(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
/**
* Finds folder icons in the current workspace.
*
@@ -569,21 +577,10 @@
expectLongClickEvents,
/* runToSpringLoadedState= */ true);
Point targetDest = getCellCenter(launcher, cellX, cellY, spanX, spanY);
- int displayX = launcher.getRealDisplaySize().x;
-
// Since the destination can be on another page, we need to drag to the edge first
// until we reach the target page
- for (int i = 0; i < destinationWorkspace; i++) {
- // Don't drag all the way to the edge to prevent touch events from getting out of
- //screen bounds.
- Point screenEdge = new Point(displayX - 1, targetDest.y);
- Point finalDragStart = dragStart;
- executeAndWaitForPageScroll(launcher,
- () -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
- true, downTime, downTime, true,
- LauncherInstrumentation.GestureScope.INSIDE));
- dragStart = screenEdge;
- }
+ dragStart = dragToGivenWorkspace(launcher, dragStart, destinationWorkspace,
+ targetDest.y);
// targetDest.x is now between 0 and displayX so we found the target page,
// we just have to put move the icon to the destination and drop it
@@ -595,6 +592,45 @@
}
}
+ /**
+ * Given a drag that already started at currentPosition, drag the item to the given destination
+ * index defined by destinationWorkspaceIndex.
+ *
+ * @param launcher
+ * @param currentPosition
+ * @param destinationWorkspaceIndex
+ * @param y
+ * @return the finishing position of the drag.
+ */
+ static Point dragToGivenWorkspace(LauncherInstrumentation launcher, Point currentPosition,
+ int destinationWorkspaceIndex, int y) {
+ final long downTime = SystemClock.uptimeMillis();
+ int displayX = launcher.getRealDisplaySize().x;
+ int currentPage = Workspace.geCurrentPage(launcher);
+ int counter = 0;
+ while (currentPage != destinationWorkspaceIndex) {
+ counter++;
+ if (counter > MAX_WORKSPACE_DRAG_TRIES) {
+ throw new RuntimeException(
+ "Wrong destination workspace index " + destinationWorkspaceIndex
+ + ", desired workspace was never reached");
+ }
+ // if the destination is greater than current page, set the display edge to be the
+ // right edge. Don't drag all the way to the edge to prevent touch events from
+ // getting out of screen bounds.
+ int displayEdge = destinationWorkspaceIndex > currentPage ? displayX - 1 : 1;
+ Point screenEdge = new Point(displayEdge, y);
+ Point finalDragStart = currentPosition;
+ executeAndWaitForPageScroll(launcher,
+ () -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
+ true, downTime, downTime, true,
+ LauncherInstrumentation.GestureScope.INSIDE));
+ currentPage = Workspace.geCurrentPage(launcher);
+ currentPosition = screenEdge;
+ }
+ return currentPosition;
+ }
+
private static void executeAndWaitForPageScroll(LauncherInstrumentation launcher,
Runnable command) {
launcher.executeAndWaitForEvent(command,