Merge "Move some Shell utils to the Shared package." into main
diff --git a/Android.bp b/Android.bp
index e358005..def024e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,6 +42,24 @@
],
}
+// Main Launcher source for compose, excluding the build config
+filegroup {
+ name: "launcher-compose-enabled-src",
+ srcs: [
+ "compose/facade/enabled/*.kt",
+ "compose/facade/core/*.kt",
+ "compose/features/**/*.kt",
+ ],
+}
+
+filegroup {
+ name: "launcher-compose-disabled-src",
+ srcs: [
+ "compose/facade/core/*.kt",
+ "compose/facade/disabled/*.kt",
+ ],
+}
+
// Source code for quickstep build, on top of launcher-src
filegroup {
name: "launcher-quickstep-src",
@@ -51,6 +69,24 @@
],
}
+// Source code for quickstep build with compose enabled, on top of launcher-src
+filegroup {
+ name: "launcher-quickstep-compose-enabled-src",
+ srcs: [
+ "quickstep/compose/facade/core/*.kt",
+ "quickstep/compose/facade/enabled/*.kt",
+ "quickstep/compose/features/**/*.kt",
+ ],
+}
+
+filegroup {
+ name: "launcher-quickstep-compose-disabled-src",
+ srcs: [
+ "quickstep/compose/facade/core/*.kt",
+ "quickstep/compose/facade/disabled/*.kt",
+ ],
+}
+
// Alternate source when quickstep is not included
filegroup {
name: "launcher-src_no_quickstep",
@@ -74,6 +110,114 @@
srcs: ["proguard.flags"],
}
+// Opt-in configuration for Launcher3 code depending on Jetpack Compose.
+soong_config_module_type {
+ name: "launcher_compose_java_defaults",
+ module_type: "java_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: ["release_enable_compose_in_launcher"],
+ properties: [
+ "srcs",
+ "static_libs",
+ ],
+}
+
+// Opt-in configuration for Launcher Quickstep code depending on Jetpack Compose.
+soong_config_bool_variable {
+ name: "release_enable_compose_in_launcher",
+}
+
+soong_config_module_type {
+ name: "quickstep_compose_java_defaults",
+ module_type: "java_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: ["release_enable_compose_in_launcher"],
+ properties: [
+ "srcs",
+ "static_libs",
+ ],
+}
+
+soong_config_module_type {
+ name: "launcher_compose_tests_java_defaults",
+ module_type: "java_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: ["release_enable_compose_in_launcher"],
+ properties: [
+ "static_libs",
+ ],
+}
+
+launcher_compose_java_defaults {
+ name: "launcher_compose_defaults",
+ soong_config_variables: {
+ release_enable_compose_in_launcher: {
+ srcs: [
+ ":launcher-compose-enabled-src"
+ ],
+
+ // Compose dependencies
+ static_libs: [
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.material3_material3",
+ ],
+
+ // By default, Compose is disabled and we compile the ComposeFacade
+ // in compose/launcher3/facade/disabled/.
+ conditions_default: {
+ srcs: [
+ ":launcher-compose-disabled-src"
+ ],
+ static_libs: [],
+ },
+ },
+ },
+}
+
+quickstep_compose_java_defaults {
+ name: "quickstep_compose_defaults",
+ soong_config_variables: {
+ release_enable_compose_in_launcher: {
+ srcs: [
+ ":launcher-quickstep-compose-enabled-src"
+ ],
+
+ // Compose dependencies
+ static_libs: [
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.material3_material3",
+ ],
+
+ // By default, Compose is disabled and we compile the ComposeFacade
+ // in compose/quickstep/facade/disabled/.
+ conditions_default: {
+ srcs: [
+ ":launcher-quickstep-compose-disabled-src"
+ ],
+ static_libs: [],
+ },
+ },
+ },
+}
+
+launcher_compose_tests_java_defaults {
+ name: "launcher_compose_tests_defaults",
+ soong_config_variables: {
+ release_enable_compose_in_launcher: {
+ // Compose dependencies
+ static_libs: [
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.ui_ui-test-junit4",
+ "androidx.compose.ui_ui-test-manifest",
+ ],
+
+ conditions_default: {
+ static_libs: [],
+ },
+ },
+ },
+}
+
android_library {
name: "launcher-aosp-tapl",
libs: [
@@ -87,6 +231,7 @@
"androidx.preference_preference",
"SystemUISharedLib",
"//frameworks/libs/systemui:animationlib",
+ "//frameworks/libs/systemui:contextualeducationlib",
"launcher-testing-shared",
],
srcs: [
@@ -147,6 +292,9 @@
// Library with all the dependencies for building Launcher3
android_library {
name: "Launcher3ResLib",
+ defaults: [
+ "launcher_compose_defaults",
+ ],
srcs: [],
resource_dirs: ["res"],
static_libs: [
@@ -164,6 +312,7 @@
"//frameworks/libs/systemui:iconloader_base",
"//frameworks/libs/systemui:view_capture",
"//frameworks/libs/systemui:animationlib",
+ "//frameworks/libs/systemui:contextualeducationlib",
"SystemUI-statsd",
"launcher-testing-shared",
"androidx.lifecycle_lifecycle-common-java8",
@@ -173,6 +322,7 @@
"kotlinx_coroutines",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
+
],
manifest: "AndroidManifest-common.xml",
sdk_version: "current",
@@ -250,6 +400,10 @@
// Library with all the source code and dependencies for building Launcher Go
android_library {
name: "Launcher3GoLib",
+ defaults: [
+ "launcher_compose_defaults",
+ "quickstep_compose_defaults",
+ ],
srcs: [
":launcher-src",
":launcher-quickstep-src",
@@ -281,6 +435,10 @@
// Library with all the source code and dependencies for building Quickstep
android_library {
name: "Launcher3QuickStepLib",
+ defaults: [
+ "launcher_compose_defaults",
+ "quickstep_compose_defaults"
+ ],
srcs: [
":launcher-src",
":launcher-quickstep-src",
@@ -308,7 +466,6 @@
// Build rule for Quickstep app.
android_app {
name: "Launcher3QuickStep",
-
static_libs: ["Launcher3QuickStepLib"],
optimize: {
proguard_flags_files: [":launcher-proguard-rules"],
@@ -349,7 +506,6 @@
// eventually be merged into a single target
android_app {
name: "Launcher3Go",
-
static_libs: ["Launcher3GoLib"],
resource_dirs: [],
@@ -386,7 +542,6 @@
}
android_app {
name: "Launcher3QuickStepGo",
-
static_libs: ["Launcher3GoLib"],
resource_dirs: [],
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index a779641..0df6c36 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -311,13 +311,6 @@
}
flag {
- name: "enable_new_archiving_icon"
- namespace: "launcher"
- description: "Archived apps will use new icon in app title"
- bug: "350758155"
-}
-
-flag {
name: "enable_multi_instance_menu_taskbar"
namespace: "launcher"
description: "Menu in Taskbar with options to launch and manage multiple instances of the same app"
@@ -329,3 +322,13 @@
description: "Settings screen supports navigating to child preference if the key is not on the screen"
bug: "293390881"
}
+
+flag {
+ name: "use_new_icon_for_archived_apps"
+ namespace: "launcher"
+ description: "Archived apps will use new cloud icon in app title instead of overlay"
+ bug: "350758155"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index f9327fe..11740ee 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -21,3 +21,13 @@
description: "Enables rewritten version of TaskThumbnailViews in Overview"
bug: "331753115"
}
+
+flag {
+ name: "enable_hover_of_child_elements_in_taskview"
+ namespace: "launcher_overview"
+ description: "Enables child elements to receive hover events in TaskView and respond visually to those hover events."
+ bug: "342594235"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/compose/facade/core/BaseComposeFacade.kt b/compose/facade/core/BaseComposeFacade.kt
new file mode 100644
index 0000000..bc7ba47
--- /dev/null
+++ b/compose/facade/core/BaseComposeFacade.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.compose.core
+
+import android.content.Context
+import android.view.View
+
+interface BaseComposeFacade {
+ fun isComposeAvailable(): Boolean
+
+ fun initComposeView(appContext: Context): View
+}
diff --git a/compose/facade/disabled/ComposeFacade.kt b/compose/facade/disabled/ComposeFacade.kt
new file mode 100644
index 0000000..c1cbfff
--- /dev/null
+++ b/compose/facade/disabled/ComposeFacade.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.compose
+
+import android.content.Context
+import android.view.View
+import com.android.launcher3.compose.core.BaseComposeFacade
+
+object ComposeFacade : BaseComposeFacade {
+ override fun isComposeAvailable(): Boolean = false
+
+ override fun initComposeView(appContext: Context): View {
+ error(
+ "Compose is not available. Make sure to check isComposeAvailable() before calling any" +
+ " other function on ComposeFacade."
+ )
+ }
+}
diff --git a/compose/facade/enabled/ComposeFacade.kt b/compose/facade/enabled/ComposeFacade.kt
new file mode 100644
index 0000000..d98a979f
--- /dev/null
+++ b/compose/facade/enabled/ComposeFacade.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.compose
+
+import android.content.Context
+import android.view.View
+import androidx.compose.ui.platform.ComposeView
+import com.android.launcher3.compose.core.BaseComposeFacade
+
+object ComposeFacade : BaseComposeFacade {
+ override fun isComposeAvailable(): Boolean = true
+
+ override fun initComposeView(appContext: Context): View = ComposeView(appContext)
+}
diff --git a/go/quickstep/res/values-be/strings.xml b/go/quickstep/res/values-be/strings.xml
index 83374bb..de8766f 100644
--- a/go/quickstep/res/values-be/strings.xml
+++ b/go/quickstep/res/values-be/strings.xml
@@ -4,7 +4,7 @@
<string name="app_share_drop_target_label" msgid="5804774105974539508">"Абагуліць праграму"</string>
<string name="action_listen" msgid="2370304050784689486">"Праслухаць"</string>
<string name="action_translate" msgid="8028378961867277746">"Перакласці"</string>
- <string name="action_search" msgid="6269564710943755464">"Аб\'ектыў"</string>
+ <string name="action_search" msgid="6269564710943755464">"Аб’ектыў"</string>
<string name="dialog_acknowledge" msgid="2804025517675853172">"ЗРАЗУМЕЛА"</string>
<string name="dialog_cancel" msgid="6464336969134856366">"СКАСАВАЦЬ"</string>
<string name="dialog_settings" msgid="6564397136021186148">"НАЛАДЫ"</string>
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index f14cebd..1b9c661 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -52,6 +52,14 @@
"tests/src/com/android/quickstep/TaplOverviewIconTest.java",
"tests/src/com/android/quickstep/TaplTestsQuickstep.java",
"tests/src/com/android/quickstep/TaplTestsSplitscreen.java",
- "tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java"
+ "tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java",
+ ],
+}
+
+filegroup {
+ name: "launcher3-quickstep-screenshot-tests-src",
+ path: "tests/multivalentScreenshotTests",
+ srcs: [
+ "tests/multivalentScreenshotTests/src/**/*.kt",
],
}
diff --git a/quickstep/compose/facade/core/QuickstepComposeFeatures.kt b/quickstep/compose/facade/core/QuickstepComposeFeatures.kt
new file mode 100644
index 0000000..ca9e5c9
--- /dev/null
+++ b/quickstep/compose/facade/core/QuickstepComposeFeatures.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.compose.core
+
+interface QuickstepComposeFeatures
diff --git a/quickstep/compose/facade/disabled/QuickstepComposeFacade.kt b/quickstep/compose/facade/disabled/QuickstepComposeFacade.kt
new file mode 100644
index 0000000..0a4345a
--- /dev/null
+++ b/quickstep/compose/facade/disabled/QuickstepComposeFacade.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.compose
+
+import android.content.Context
+import com.android.launcher3.compose.ComposeFacade
+import com.android.launcher3.compose.core.BaseComposeFacade
+import com.android.quickstep.compose.core.QuickstepComposeFeatures
+
+object QuickstepComposeFacade : BaseComposeFacade, QuickstepComposeFeatures {
+
+ override fun isComposeAvailable() = ComposeFacade.isComposeAvailable()
+
+ override fun initComposeView(appContext: Context) = ComposeFacade.initComposeView(appContext)
+}
diff --git a/quickstep/compose/facade/enabled/QuickstepComposeFacade.kt b/quickstep/compose/facade/enabled/QuickstepComposeFacade.kt
new file mode 100644
index 0000000..97cd300
--- /dev/null
+++ b/quickstep/compose/facade/enabled/QuickstepComposeFacade.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.compose
+
+import android.content.Context
+import com.android.launcher3.compose.ComposeFacade
+import com.android.launcher3.compose.core.BaseComposeFacade
+import com.android.quickstep.compose.core.QuickstepComposeFeatures
+
+object QuickstepComposeFacade : BaseComposeFacade, QuickstepComposeFeatures {
+ override fun isComposeAvailable() = ComposeFacade.isComposeAvailable()
+
+ override fun initComposeView(appContext: Context) = ComposeFacade.initComposeView(appContext)
+}
diff --git a/quickstep/res/drawable/bg_circle.xml b/quickstep/res/drawable/bg_circle.xml
deleted file mode 100644
index 506177b..0000000
--- a/quickstep/res/drawable/bg_circle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 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="oval">
- <solid android:color="#FFFFFFFF" />
-</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_desktop.xml b/quickstep/res/drawable/ic_desktop.xml
index 8de275d..11feca5 100644
--- a/quickstep/res/drawable/ic_desktop.xml
+++ b/quickstep/res/drawable/ic_desktop.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?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");
@@ -15,17 +14,13 @@
~ 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:color/black"
- 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>
+ android:width="24dp"
+ android:height="24dp"
+ android:autoMirrored="true"
+ android:tint="?attr/colorControlNormal"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@android:color/black"
+ android:pathData="M240,640L600,640L600,440L240,440L240,640ZM660,520L720,520L720,320L360,320L360,380L660,380L660,520ZM160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,240Q800,240 800,240Q800,240 800,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720ZM160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720Z" />
</vector>
diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml
index 797ea45..a11974c 100644
--- a/quickstep/res/layout/split_instructions_view.xml
+++ b/quickstep/res/layout/split_instructions_view.xml
@@ -41,5 +41,6 @@
android:textColor="?androidprv:attr/textColorOnAccent"
android:layout_marginStart="@dimen/split_instructions_start_margin_cancel"
android:text="@string/toast_split_select_app_cancel"
+ android:textStyle="bold"
android:visibility="gone"/>
</com.android.quickstep.views.SplitInstructionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index ac1a50a..34193d3 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -19,7 +19,7 @@
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:id="@+id/task"
+ android:id="@+id/task_view_single"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 64aa7e1..1564653 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?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");
@@ -15,20 +14,19 @@
limitations under the License.
-->
-<com.android.quickstep.views.DesktopTaskView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+<com.android.quickstep.views.DesktopTaskView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:id="@+id/task"
+ android:id="@+id/task_view_desktop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="true"
+ android:clipToPadding="true"
+ android:contentDescription="@string/recent_task_desktop"
android:defaultFocusHighlightEnabled="false"
android:focusable="true"
+ android:padding="0.1dp"
launcher:focusBorderColor="?attr/materialColorOutline"
- launcher:hoverBorderColor="?attr/materialColorPrimary"
- android:clipToPadding="true"
- android:padding="0.1dp">
+ launcher:hoverBorderColor="?attr/materialColorPrimary">
<!-- Setting a padding of 0.1 dp since android:clipToPadding needs a non-zero value for
padding to work-->
<View
@@ -38,8 +36,8 @@
<ViewStub
android:id="@+id/icon"
- android:inflatedId="@id/icon"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
+ android:inflatedId="@id/icon" />
</com.android.quickstep.views.DesktopTaskView>
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index da2b29f..cb4b98f 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -24,7 +24,7 @@
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:id="@+id/task"
+ android:id="@+id/task_view_grouped"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index 736706a..e8f3d9d 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -35,6 +35,18 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
+ <com.android.launcher3.taskbar.bubbles.BubbleBarView
+ android:id="@+id/taskbar_bubbles"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/bubblebar_size_with_pointer"
+ android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
+ android:paddingTop="@dimen/bubblebar_pointer_visible_size"
+ android:visibility="gone"
+ android:gravity="center"
+ android:layout_gravity="bottom"
+ android:clipChildren="false"
+ android:elevation="@dimen/bubblebar_elevation" />
+
<com.android.launcher3.taskbar.navbutton.NearestTouchFrame
android:id="@+id/navbuttons_view"
android:layout_width="match_parent"
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index f8c8977..c109328 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Stoor app-paar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tik op ’n ander app om verdeelde skerm te gebruik"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Kies ’n ander app as jy verdeelde skerm wil gebruik"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Kanselleer"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Verlaat verdeeldeskermkeuse"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kitsinstellings"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taakbalk"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taakbalk word gewys"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taakbalk en borrels wys links"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taakbalk en borrels wys regs"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taakbalk is versteek"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taakbalk en borrels is versteek"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasiebalk"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Wys altyd Taakbalk"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Verander navigasiemodus"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index f5cef7b..f144118 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"የመተግበሪያ ጥምረትን አስቀምጥ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ ይምረጡ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ይቅር"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ከተከፈለ ማያ ገፅ ምርጫ ይውጡ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"የተከፈለ ማያ ገጽን ለመቀበል ሌላ መተግበሪያ ይምረጡ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ፈጣን ቅንብሮች"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"የተግባር አሞሌ"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"የተግባር አሞሌ ይታያል"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"የተግባር አሞሌ እና አረፋዎች በግራ በኩል ይታያሉ"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"የተግባር አሞሌ እና አረፋዎች በቀኝ በኩል ይታያሉ"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"የተግባር አሞሌ ተደብቋል"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"የተግባር አሞሌ እና አረፋዎች ተደብቀዋል"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"የአሰሳ አሞሌ"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ሁልጊዜ የተግባር አሞሌ ያሳዩ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"የአሰሳ ሁነታን ይለውጡ"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 52a18e9..629580f 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"حفظ استخدام التطبيقين معًا"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"اختَر تطبيقًا آخر لاستخدام \"وضع تقسيم الشاشة\""</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"إلغاء"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"إلغاء"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"الخروج من وضع تقسيم الشاشة"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام \"وضع تقسيم الشاشة\""</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"إعدادات سريعة"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"شريط التطبيقات"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"تم إظهار شريط التطبيقات"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"يتم عرض \"شريط التطبيقات\" و\"فقاعات المحادثات\" يمينًا"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"يتم عرض \"شريط التطبيقات\" و\"فقاعات المحادثات\" يسارًا"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"تم إخفاء شريط التطبيقات"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"تم إخفاء \"شريط التطبيقات\" و\"فقاعات المحادثات\""</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"شريط التنقل"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"إظهار شريط التطبيقات دائمًا"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"تغيير وضع التنقل"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index d811543..252697c 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"এপৰ পেয়াৰ ছেভ কৰক"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছনি কৰক"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল কৰক"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"বাতিল কৰক"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"বিভাজিত স্ক্ৰীনৰ বাছনিৰ পৰা বাহিৰ হওক"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছক"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এপ্টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 3108ffe..7d7ed56 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Tətbiq cütünü saxla"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran üçün başqa tətbiqə toxunun"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ləğv edin"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Bölünmüş ekran seçimindən çıxın"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Sürətli Ayarlar"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Tapşırıq paneli"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"İşləmə paneli göstərilir"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"İşləmə paneli, yumrucuqlar solda göstərilir"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"İşləmə paneli, yumrucuqlar sağda göstərilir"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"İşləmə paneli gizlədilib"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"İşləmə paneli, yumrucuqlar gizlədilib"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naviqasiya paneli"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"İşləmə paneli həmişə görünsün"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Naviqasiya rejimini dəyişin"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index e6074b0..d8f608d 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da biste koristili podeljeni ekran"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izlazak iz biranja podeljenog ekrana"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brza podešavanja"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Traka zadataka je prikazana"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Prikaz zadataka/oblačića levo"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Prikaz zadataka/oblačića desno"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Traka zadataka je skrivena"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Skriveni zadaci/oblačići"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Traka za navigaciju"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Uvek prikazuj traku zadataka"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Promeni režim navigacije"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 5b871d4..b403e7f 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -39,7 +39,7 @@
<string name="hotseat_edu_accept" msgid="1611544083278999837">"Атрымліваць прапановы праграм"</string>
<string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Не, дзякуй"</string>
<string name="hotseat_prediction_settings" msgid="6246554993566070818">"Налады"</string>
- <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Тут з\'яўляюцца праграмы, якімі вы карыстаецеся найбольш часта. Гэты спіс змяняецца на падставе вашых дзеянняў"</string>
+ <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Тут з’яўляюцца праграмы, якімі вы карыстаецеся найбольш часта. Гэты спіс змяняецца на падставе вашых дзеянняў"</string>
<string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Перацягніце праграмы з ніжняга радка, каб атрымліваць прапановы праграм"</string>
<string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Прапановы праграм дададзены на свабоднае месца"</string>
<string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Прапановы праграм уключаны"</string>
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Захаваць спалучэнне"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Каб падзяліць экран, націсніце на іншую праграму"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Каб карыстацца рэжымам падзеленага экрана, выберыце другую праграму"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасаваць"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Скасаваць"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Выйсці з рэжыму падзеленага экрана"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Каб падзяліць экран, выберыце іншую праграму"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Хуткія налады"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Панэль задач"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Панэль задач паказана"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Панэль задач і ўсплывальныя чаты паказваюцца злева"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Панэль задач і ўсплывальныя чаты паказваюцца справа"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Панэль задач схавана"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Панэль задач і ўсплывальныя чаты схаваны"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панэль навігацыі"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Заўсёды паказваць панэль задач"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Змяніць рэжым навігацыі"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index dd87de8..6fb6127 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Запис на двойка приложения"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Докоснете друго прил., за да ползвате разд. екран"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"За разделен екран изберете още едно приложение"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отказ"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Отказ"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Изход от избора на разделен екран"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"За разделен екран изберете още едно приложение"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Това действие не е разрешено от приложението или организацията ви"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Бързи настройки"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Лента на задачите"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Лентата на задачите се показва"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Лентата и балончетата са вляво"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Лентата и балончетата са вдясно"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Лентата на задачите е скрита"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Лентата и балончетата са скрити"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигация"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Лентата на задачите винаги да се показва"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Промяна на режима на навигация"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 99a815f..043c0d6 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"অ্যাপ পেয়ার সেভ করুন"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"স্প্লিট স্ক্রিন ব্যবহারের জন্য অ্যাপে ট্যাপ করুন"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল করুন"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"স্প্লিট স্ক্রিন বেছে নেওয়ার বিকল্প থেকে বেরিয়ে আসুন"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"দ্রুত সেটিংস"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"টাস্কবার"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"\'টাস্কবার\' দেখানো হয়েছে"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"টাস্কবার ও বাবল বাঁদিকে দেখানো হয়েছে"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"টাস্কবার ও বাবল ডানদিকে দেখানো হয়েছে"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"\'টাস্কবার\' লুকানো রয়েছে"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"টাস্কবার ও বাবল লুকানো হয়েছে"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"নেভিগেশন বার"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"সবসময় টাস্কবার দেখুন"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"\'নেভিগেশন\' মোড পরিবর্তন করুন"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 5f445ab..af7fe61 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -92,14 +92,14 @@
<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">"Spremni ste da počnete koristiti <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
- <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigiranja sistemom"</annotation></string>
+ <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sistemom"</annotation></string>
<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>
<string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da koristite podijeljeni ekran"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Odustani"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izlaz iz odabira podijeljenog ekrana"</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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brze postavke"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Traka zadataka je prikazana"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Traka zadataka/oblačići prik. lijevo"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Traka zadataka/oblačići prik. desno"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Traka zadataka je sakrivena"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Traka zadataka/oblačići sakriveni"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigaciona traka"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Uvijek prikaži traku zadataka"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Promijeni način navigacije"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 2b8fadf..cc3112a 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format lliure"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinador"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escriptori"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
<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>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Desa la parella d\'apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toca una altra app per utilitzar pantalla dividida"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Tria una altra aplicació per utilitzar la pantalla dividida"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel·la"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Surt de la selecció de 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. ràpida"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tasques"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Es mostra la Barra de tasques"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra i bombolles a l\'esquerra"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra i bombolles a la dreta"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"S\'ha amagat la Barra de tasques"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra i bombolles amagades"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegació"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tasques sempre visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Canvia el mode de navegació"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 6e432de..546aa1e 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Uložit dvojici aplikací"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdělíte klepnutím na jinou aplikaci"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Výběrem další aplikace rozdělíte obrazovku"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušit"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Výběr opuštění rozdělené obrazovky"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rychlé nastavení"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Panel aplikací"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Panel aplikací je zobrazen"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Panel a bubliny vlevo zobr."</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Panel a bubliny vpravo zobr."</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Panel aplikací je skrytý"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Panel a bubliny jsou skryty"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigační panel"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Vždy zobrazovat panel aplikací"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Změnit režim navigace"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index c73f49c..ae10343 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Gem appsammenknytning"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Vælg en anden app for at bruge opdelt skærm"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuller"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Luk valg af 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kvikmenu"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Proceslinje"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Proceslinjen vises"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Proceslinje og bobler til venstre"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Proceslinje og bobler til højre"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Proceslinjen er skjult"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Proceslinje og bobler skjult"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationslinje"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Vis altid proceslinjen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Skift navigationstilstand"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 8f571ce..03b5bb9 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"App-Paar speichern"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Für Splitscreen auf weitere App tippen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Für Splitscreen andere App auswählen"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Abbrechen"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Splitscreen-Auswahl beenden"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Für Splitscreen andere App auswählen"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Schnelleinstellungen"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskleiste"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskleiste eingeblendet"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskleiste & Bubbles links eingeblendet"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskleiste & Bubbles rechts eingeblendet"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskleiste ausgeblendet"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskleiste & Bubbles ausgeblendet"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationsleiste"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Taskleiste immer anzeigen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigationsmodus ändern"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 011c800..a717678 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -67,7 +67,7 @@
<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>
- <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Αρχική"</string>
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Μετάβαση στην αρχική οθόνη"</string>
<string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Σύρετε προς τα επάνω από το κάτω μέρος της οθόνης"</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Μπράβο!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Φροντίστε να σύρετε προς τα επάνω από το κάτω άκρο της οθόνης"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Αποθήκ. ζεύγ. εφαρμ."</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Πατήστε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ακύρωση"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Έξοδος από την επιλογή διαχωρισμού οθόνης"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Γρήγορες ρυθμ."</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Γραμμή εργαλείων"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Η γραμμή εργαλείων εμφανίζεται"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Εμφάν. αριστ. γρ. εργ. και συν."</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Εμφάν. δεξιάς γρ. εργ. και συν."</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Η γραμμή εργαλείων είναι κρυφή"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Απόκρυψη εργαλείων και συννεφ."</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Γραμμή πλοήγησης"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Εμφάνιση Γραμμής εργαλείων"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Αλλαγή τρόπου πλοήγησης"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index c63e094..d28cbf0 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar shown"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar and bubbles left shown"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar and bubbles right shown"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar hidden"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar and bubbles hidden"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 2183919..e069b8f 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancel"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</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>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index c63e094..d28cbf0 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar shown"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar and bubbles left shown"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar and bubbles right shown"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar hidden"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar and bubbles hidden"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index c63e094..d28cbf0 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar shown"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar and bubbles left shown"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar and bubbles right shown"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar hidden"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar and bubbles hidden"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index ba55585..777db28 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639">""<b>"Cancel"</b>""</string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancel"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</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>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 7df97ef..3d78c71 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Guardar vinculación"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Presiona otra app para usar la pantalla dividida"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Salir de la selección de pantalla dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. rápida"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tareas"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tareas visible"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra tareas y burb. a la izq."</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra tareas y burb. a la der."</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tareas oculta"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra tareas y burb. ocultas"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 353ff4c..f878954 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordenador"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay nada reciente"</string>
<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>
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Guardar apps emparejadas"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toca otra aplicación para usar la pantalla dividida"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Salir de la selección de pantalla dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ajustes rápidos"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tareas"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tareas visible"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Tareas y burbujas a izquierda"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Tareas y burbujas a derecha"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tareas oculta"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Tareas y burbujas ocultas"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 6b78c1f..4468533 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -72,7 +72,7 @@
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Väga hea!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pühkige kindlasti ekraani alumisest servast üles."</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Hoidke sõrme aknal pisut kauem, enne kui vabastate"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pühkige kindlasti otse üles, seejärel peatuge"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pühkige kindlasti otse üles, seejärel peatuge."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Õppisite liigutusi kasutama. Liigutuste väljalülitamiseks avage Seaded."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Tegite rakenduste vahel vahetamise liigutuse"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Pühkige rakenduste vahetamiseks"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Tühista"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Jagatud ekraanikuva valikust väljumine"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kiirseaded"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Tegumiriba"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Tegumiriba on kuvatud"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Tegumiriba ja mullid kuvatakse"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Tegumiriba ja mullid kuvatakse paremal"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Tegumiriba on peidetud"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Tegumiriba ja mullid on peidetud"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeerimisriba"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Kuva tegumiriba alati"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigeerimisrežiimi muutmine"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 058ade5..fe138b8 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Gorde aplikazio parea"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pantaila zatitua erabiltzeko, aukeratu beste aplikazio bat"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Utzi"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Irten pantaila zatituaren hautapenetik"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pantaila zatitzeko, aukeratu beste aplikazio bat"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ezarpen bizkorrak"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Zereginen barra"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Zereginen barra ikusgai dago"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Zereginen barra eta burbuilak ezkerrean ikusgai"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Zereginen barra eta burbuilak eskuinean ikusgai"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Zereginen barra itxita dago"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Zereginen barra eta burbuilak ezkutatuta"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Nabigazio-barra"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Erakutsi beti zereginen barra"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Aldatu nabigazio modua"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index f6f51b7..cb88eba 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"رایانه"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"حالت رایانه"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"چیز جدیدی اینجا نیست"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ذخیره جفت برنامه"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"زدن روی برنامهای دیگر برای استفاده از صفحه دونیمه"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"انتخاب برنامهای دیگر برای استفاده از صفحه دونیمه"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"لغو کردن"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"لغو کردن"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"خروج از انتخاب صفحهٔ دونیمه"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"انتخاب برنامهای دیگر برای استفاده از صفحه دونیمه"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمیدهد این کنش انجام شود."</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"تنظیمات فوری"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"نوار وظیفه"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"نوار وظیفه نمایان است"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"نمایش نوار وظیفه و حبابکها در چپ"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"نمایش نوار وظیفه و حبابکها در راست"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"نوار وظیفه پنهان است"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"نوار وظیفه و حبابکها پنهان هستند"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نوار پیمایش"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"نوار وظیفه همیشه نشان داده شود"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"تغییر حالت پیمایش"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 91f64ed..4d610f2 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Tallenna pari"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Peruuta"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Poistu jaetun näytön valinnasta"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Pika-asetukset"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Tehtäväpalkki"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Tehtäväpalkki näkyvissä"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Vas. palkki ja kuplat näkyvissä"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Oik. palkki ja kuplat näkyvissä"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Tehtäväpalkki piilotettu"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Palkki ja kuplat piilotettu"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigointipalkki"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Näytä tehtäväpalkki aina"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Vaihda navigointitilaa"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index e567239..179be5f 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Enr. paire d\'applis"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choisir une autre appli pour utiliser l\'Écran divisé"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuler"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Quitter la sélection d\'écran divisé"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre appli pour utiliser l\'écran partagé"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'appli ou votre organisation n\'autorise pas cette action"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Paramètres rapides"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barre des tâches"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barre des tâches affichée"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barre des tâches/bulles à gauche"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barre des tâches/bulles à droite"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barre des tâches masquée"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barre des tâches/bulles masquées"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Tjrs afficher barre des tâches"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Changer de mode de navigation"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index ddab232..8568c40 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -88,7 +88,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="459504134589971527">"Balayez l\'écran vers le haut pour revenir à l\'accueil"</string>
+ <string name="allset_hint" msgid="459504134589971527">"Balayez 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>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Enregistrer la paire d\'applis"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Appuyez sur autre appli pour l\'écran partagé"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Sélectionnez une autre appli pour utiliser l\'écran partagé."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Quitter la sélection de 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Réglages rapides"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barre des tâches"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barre des tâches affichée"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barre des tâches et bulles affichées à gauche"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barre des tâches et bulles affichées à droite"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barre des tâches masquée"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barre des tâches et bulles masquées"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Barre des tâches tjs visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Modifier le mode de navigation"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 053a48f..e6400ca 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -90,7 +90,7 @@
<string name="allset_title" msgid="5021126669778966707">"Todo listo"</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="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> xa está dispoñible para comezar a utilizar"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configuración da navegación do sistema"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Gardar parella apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolle outra aplicación para usar a pantalla dividida."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Saír da selección de pantalla dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolle outra app para usar a pantalla dividida"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Configuración rápida"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Estase mostrando a barra de tarefas"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra e burbullas á esquerda"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra e burbullas á dereita"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Non se está mostrando a barra de tarefas"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra e burbullas ocultas"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre a barra de tarefas"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar modo de navegación"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index a081ab5..2adf594 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ઍપની જોડી સાચવો"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"વિભાજિત સ્ક્રીન વાપરવા, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"વિભાજિત સ્ક્રીનની સુવિધાનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"રદ કરો"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"\'સ્ક્રીનને વિભાજિત કરો\' પસંદગીમાંથી બહાર નીકળો"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"સ્ક્રીન વિભાજનનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ઝડપી સેટિંગ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ટાસ્કબાર"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ટાસ્કબાર બતાવવામાં આવ્યો"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ટાસ્કબાર અને બબલ ડાબે બતાવ્યા"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ટાસ્કબાર અને બબલ જમણે બતાવ્યા"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ટાસ્કબાર છુપાવવામાં આવ્યો"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ટાસ્કબાર અને બબલ છુપાવેલા છે"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"નૅવિગેશન બાર"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"હંમેશાં ટાસ્કબાર બતાવો"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"નૅવિગેશન મોડ બદલો"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 1e74c4a..56d2b39 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -92,14 +92,14 @@
<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>
- <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"सिस्टम नेविगेशन सेटिंग"</annotation></string>
+ <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"सिस्टम नेविगेशन से जुड़ी सेटिंग"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"शेयर करें"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"ऐप पेयर सेव करें"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन के लिए दूसरे ऐप्लिकेशन पर टैप करें"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रीन इस्तेमाल करने के लिए, दूसरा ऐप्लिकेशन चुनें"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"अभी नहीं"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"अभी नहीं"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"स्प्लिट स्क्रीन मोड से बाहर निकलें"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन के लिए, दूसरा ऐप्लिकेशन चुनें"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"फटाफट सेटिंग"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"टास्कबार दिखाया गया"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"टास्कबार और बबल बाईं ओर हैं"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"टास्कबार और बबल दाईं ओर हैं"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"टास्कबार छिपाया गया"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"टास्कबार और बबल छिपाए गए"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेविगेशन बार"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार हमेशा दिखाएं"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"नेविगेशन का मोड बदलें"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index fc85be9..97f4ee0 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Spremi par apl."</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju za upotrebu podijeljenog zaslona"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Odustani"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Odustani"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Zatvori odabir podijeljenog zaslona"</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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brze postavke"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka sa zadacima"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Traka sa zadacima prikazana"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Traka sa zadacima/oblačići prikazani lijevo"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Traka sa zadacima/oblačići prikazani desno"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Traka sa zadacima skrivena"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Traka sa zadacima/oblačići skriveni"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigacijska traka"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Uvijek prikaži traku zadataka"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Promijeni način navigacije"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 3a539d4..2d0bd18 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"App-pár mentése"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Koppintson másik appra az osztott képernyőhöz"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Válasszon másik appot a képernyő felosztásához"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Mégse"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Kilépés az osztott képernyő elemeinek kiválasztásából"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Gyorsbeállítások"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Tálca"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Feladatsáv megjelenítve"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Feladatsáv és buborék balra"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Feladatsáv és buborék jobbra"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Feladatsáv elrejtve"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Rejtett feladatsáv és buborék"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigációs sáv"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Mindig megjelenő Feladatsáv"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigációs mód módosítása"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index d8503f3..947e34e 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Պահել հավելվ․ զույգը"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Հպեք այլ հավելվածի՝ տրոհված էկրանից օգտվելու համար"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Ընտրեք այլ հավելված՝ տրոհված էկրանից օգտվելու համար"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Չեղարկել"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Չեղարկել"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Դուրս գալ տրոհված էկրանի ռեժիմից"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ընտրեք այլ հավելված՝ տրոհված էկրանից օգտվելու համար"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Արագ կարգավորումներ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Խնդրագոտի"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Խնդրագոտին ցուցադրվում է"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Հավելվածների վահանակն ու ամպիկները տեսանելի են ձախ կողմում"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Հավելվածների վահանակն ու ամպիկները տեսանելի են աջ կողմում"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Խնդրագոտին թաքցված է"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Հավելվածների վահանակն ու ամպիկները թաքցված են"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Նավիգացիայի գոտի"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Միշտ ցույց տալ վահանակը"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Փոխել նավիգացիայի ռեժիմը"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index d4def8d..16334ca 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -79,7 +79,7 @@
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Untuk beralih dari satu aplikasi ke aplikasi lain, geser ke atas dari bagian bawah layar, tahan, lalu lepaskan."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Untuk beralih antar-aplikasi, geser ke atas dengan 2 jari dari bawah layar, tahan, lalu lepaskan."</string>
<string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Beralih aplikasi"</string>
- <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Geser ke atas dari bagian bawah layar, tahan, kemudian lepaskan"</string>
+ <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Geser ke atas dari bagian bawah layar, tahan, kemudian lepas"</string>
<string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Bagus."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Semua siap"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Selesai"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Simpan pasangan apl"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Ketuk aplikasi lain untuk memakai layar terpisah"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pilih aplikasi lain untuk dibuka di layar terpisah"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Batal"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Keluar dari pemilihan layar terpisah"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih aplikasi lain untuk dibuka di layar terpisah"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Setelan Cepat"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar ditampilkan"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar & balon kiri ditampilkan"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar & bubbles kanan ditampilkan"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar disembunyikan"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar & balon disembunyikan"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Menu navigasi"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Selalu tampilkan Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Ubah mode navigasi"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index f2dd60c..ed1cf85 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Vista forritapar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Ýttu á annað forrit til að nota skjáskiptingu"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Veldu annað forrit til að nota skjáskiptingu"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Hætta við"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Loka 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Flýtistillingar"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Verkstika"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Forritastika sýnd"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Verkstika og blöðrur sýndar til vinstri"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Verkstika og blöðrur sýndar til hægri"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Forritastika falin"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Verkstika og blöðrur eru faldar"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Yfirlitsstika"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Alltaf sýna forritastiku"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Breyta leiðsagnarstillingu"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 9ed28c1..29a84dd 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Salva coppia di app"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tocca un\'altra app per usare lo schermo diviso"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Scegli un\'altra app per usare lo schermo diviso"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annulla"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Esci dalla selezione dello 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>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index da8b37d..e30f7df 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -88,7 +88,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="459504134589971527">"כדי לחזור לדף הבית, מחליקים כלפי מעלה"</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>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"שמירת צמד אפליקציות"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"צריך להקיש על אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ביטול"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"יציאה מתצוגת מסך מפוצל"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"הגדרות מהירות"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"סרגל האפליקציות"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"סרגל האפליקציות מוצג"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"סרגל האפליקציות והבועות מוצגים משמאל"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"סרגל האפליקציות והבועות מוצגים מימין"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"סרגל האפליקציות מוסתר"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"סרגל האפליקציות והבועות הוסתרו"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"סרגל הניווט"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"סרגל האפליקציות מוצג תמיד"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"שינוי מצב הניווט"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 54f51da..bb6d07b 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"フリーフォーム"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"パソコン"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"デスクトップ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"アプリのペア設定保存"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"分割画面を使用するには、他のアプリをタップします"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"分割画面を使用するには別のアプリを選択してください"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"キャンセル"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"キャンセル"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"分割画面の選択を終了します"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"分割画面にするには、別のアプリを選択してください"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 5328012..0ffc3e8 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"აპთა წყვილის შენახვა"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"შეეხეთ სხვა აპს ეკრანის გასაყოფად"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"აირჩიეთ სხვა აპი ეკრანის გასაყოფად"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"გაუქმება"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"გაუქმება"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ეკრანის გაყოფის არჩევანიდან გასვლა"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"აირჩიეთ სხვა აპი ეკრანის გასაყოფად"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ეს მოქმედება არ არის დაშვებული აპის ან თქვენი ორგანიზაციის მიერ"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"სწრაფი პარამეტრები"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ამოცანათა ზოლი"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ამოცანათა ზოლი ნაჩვენებია"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ამოცანათა ზოლი და ბუშტები ჩანს მარცხნივ"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ამოცანათა ზოლი და ბუშტები ჩანს მარჯვნივ"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ამოცანათა ზოლი დამალულია"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ამოცანათა ზოლი და ბუშტები დამალულია"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ნავიგაციის ზოლი"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ამოცანათა ზოლის მუდამ ჩვენება"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"შეცვალეთ ნავიგაციის რეჟიმი"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 54c1795..8bf7111 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Қолданбаларды жұптауды сақтау"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Бас тарту"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Экранды бөлу режимінен шығу"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Жылдам параметрлер"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Тапсырмалар жолағы"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Тапсырмалар жолағы көрсетілді"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Тапсырмалар жолағы мен қалқыма терезелер сол жақта көрсетілген"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Тапсырмалар жолағы мен қалқыма терезелер оң жақта көрсетілген"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Тапсырмалар жолағы жасырылды"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Тапсырмалар жолағы мен қалқыма терезелер жасырылған"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигация жолағы"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Тапсырма жолағын үнемі көрсету"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Навигация режимін өзгерту"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 698f33c..06cd015 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ខ្ទាស់"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"មុខងារទម្រង់សេរី"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"កុំព្យូទ័រ"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ដែសថប"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ការកំណត់ការប្រើប្រាស់កម្មវិធី"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"សម្អាតទាំងអស់"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"រក្សាទុកគូកម្មវិធី"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ចុចកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"បោះបង់"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ចាកចេញពីការជ្រើសរើសរបស់មុខងារបំបែកអេក្រង់"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះមិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី ឬស្ថាប័នរបស់អ្នកទេ"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ការកំណត់រហ័ស"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"របារកិច្ចការ"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"បានបង្ហាញរបារកិច្ចការ"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"បានបង្ហាញរបារកិច្ចការ និងផ្ទាំងអណ្ដែតនៅខាងឆ្វេង"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"បានបង្ហាញរបារកិច្ចការ និងផ្ទាំងអណ្ដែតនៅខាងស្ដាំ"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"បានលាក់របារកិច្ចការ"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"បានលាក់របារកិច្ចការ និងផ្ទាំងអណ្ដែត"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"របាររុករក"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"បង្ហាញរបារកិច្ចការជានិច្ច"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ប្ដូរមុខងាររុករក"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 6a86e38..26f1d6f 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಇನ್ನೊಂದು ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ರದ್ದುಮಾಡಿ"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ರದ್ದುಮಾಡಿ"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಆಯ್ಕೆಯಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"\"ಪರದೆ ಬೇರ್ಪಡಿಸಿ\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ಟಾಸ್ಕ್ಬಾರ್"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ಟಾಸ್ಕ್ಬಾರ್ ತೋರಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ಟಾಸ್ಕ್ಬಾರ್ & ಬಬಲ್ಸ್ ತೋರಿಸಲಾಗಿದೆ"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ಟಾಸ್ಕ್ಬಾರ್ & ಬಬಲ್ಸ್ ಬಲಭಾಗದಲ್ಲಿ ತೋರಿಸಲಾಗಿದೆ"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ಟಾಸ್ಕ್ಬಾರ್ ಮರೆಮಾಡಲಾಗಿದೆ"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ಟಾಸ್ಕ್ಬಾರ್ & ಬಬಲ್ಸ್ ಮರೆಮಾಡಲಾಗಿದೆ"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ಯಾವಾಗಲೂ ಟಾಸ್ಕ್ಬಾರ್ ತೋರಿಸಿ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ನ್ಯಾವಿಗೇಶನ್ ಮೋಡ್ ಬದಲಾಯಿಸಿ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 31942fb..04fd457 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -90,7 +90,7 @@
<string name="allset_title" msgid="5021126669778966707">"설정 완료"</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="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> 사용 준비가 완료되었습니다."</string>
<string name="default_device_name" msgid="6660656727127422487">"기기"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"시스템 탐색 설정"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"공유"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"앱 페어링 저장"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"다른 앱을 탭하여 화면 분할 사용"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"취소"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"화면 분할 선택 종료"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"이 작업은 앱 또는 조직에서 허용되지 않습니다."</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"빠른 설정"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"태스크 바"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"태스크 바 표시"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"태스크 바와 대화창을 왼쪽에 표시"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"태스크 바와 대화창을 오른쪽에 표시"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"태스크 바 숨김"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"태스크 바 및 대화창 숨김"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"탐색 메뉴"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"태스크 바 항상 표시"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"탐색 모드 변경"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 8805bd0..f0156de 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -90,7 +90,7 @@
<string name="allset_title" msgid="5021126669778966707">"Бүттү!"</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="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> колдоно берсеңиз болот"</string>
<string name="default_device_name" msgid="6660656727127422487">"түзмөк"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Өтүү аракетинин системалык параметрлери"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Колдонмолорду сактап коюу"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Жокко чыгаруу"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Тандалган экранды бөлүүдөн чыгуу"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ыкчам параметрлер"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Тапшырмалар тактасы"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Тапшырмалар панели көрсөтүлдү"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Тапшырмалар панели, калкыма билдирмелер сол жакта көрсөтүлдү"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Тапшырмалар панели, калкыма билдирмелер оң жакта көрсөтүлгөн"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Тапшырмалар панели жашырылды"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Тапшырмалар панели жана калкып чыкма билдирмелер жашырылган"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Чабыттоо тилкеси"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Такта ар дайым көрүнсүн"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Өтүү режимин өзгөртүү"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 9e70a5c..81a52b1 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ບັນທຶກຈັບຄູ່ແອັບ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ແຕະແອັບອື່ນເພື່ອໃຊ້ໜ້າຈໍແຍກ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ຍົກເລີກ"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ອອກຈາກາກນເລືອກການແບ່ງໜ້າຈໍ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ການຕັ້ງຄ່າດ່ວນ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ແຖບໜ້າວຽກ"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ແຖບໜ້າວຽກທີ່ສະແດງຢູ່"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ແຖບໜ້າວຽກ ແລະ ຟອງສະແດງຢູ່ເບື້ອງຊ້າຍ"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ແຖບໜ້າວຽກ ແລະ ຟອງສະແດງຢູ່ເບື້ອງຂວາ"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ແຖບໜ້າວຽກທີ່ເຊື່ອງໄວ້ຢູ່"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ແຖບໜ້າວຽກ ແລະ ຟອງຖືກເຊື່ອງໄວ້"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ແຖບການນຳທາງ"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ສະແດງແຖບໜ້າວຽກສະເໝີ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ປ່ຽນໂໝດການນຳທາງ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index f78fa30..ec45620 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Išsaug. progr. porą"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Išskaidyto ekrano režimas palietus kitą programą"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Išskaidyto ekrano režimą naudokite kita programa"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Atšaukti"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Išeiti iš išskaidyto ekrano pasirinkimo"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Spartieji nustatymai"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Užduočių juosta"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Užduočių juosta rodoma"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Užduočių juosta ir burbulai rodomi kairėje"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Užduočių juosta ir burbulai rodomi dešinėje"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Užduočių juosta paslėpta"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Užduočių juosta ir burbulai paslėpti"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naršymo juosta"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Visada rodyti užduočių juostą"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Keisti naršymo režimą"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 799e8d1..4474e7c 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Saglabāt pāri"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Lai sadalītu ekrānu, pieskarieties citai lietotnei"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Atcelt"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izejiet no ekrāna sadalīšanas režīma atlases."</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ātrie iestatīj."</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Uzdevumu josla"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Uzdevumu josla tiek rādīta"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Uzdevumu josla/burbuļi pa kreisi"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Uzdevumu josla/burbuļi pa labi"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Uzdevumu josla paslēpta"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Uzdevumu josla/burbuļi paslēpti"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigācijas josla"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Vienmēr rādīt uzdevumu joslu"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Mainīt navigācijas režīmu"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 04f35ba..f503e59 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компјутер"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Работна површина"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Поставки за користење на апликациите"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Избриши ги сите"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Зачувај го паров"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Допрете друга аплик. за да користите поделен екран"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Изберете друга апликација за да користите поделен екран"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Излези од изборот на поделен екран"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Изберете друга апликација за да користите поделен екран"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брзи поставки"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Лента со задачи"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Лентата со задачи е прикажана"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Лен. со зад. и бал. се лево"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Лен. со зад. и бал. се десно"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Лентата со задачи е скриена"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Лен. со зад. и бал. се скриени"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигација"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Секогаш прикажувај „Лента“"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Променете режим на навигација"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 0db3e1f..5448f60 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ആപ്പ് ജോടി സംരക്ഷിക്കൂ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"സ്പ്ലിറ്റ് സ്ക്രീനിന് മറ്റൊരു ആപ്പിൽ ടാപ്പ് ചെയ്യൂ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കാൻ മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"റദ്ദാക്കുക"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"സ്ക്രീൻ വിഭജന തിരഞ്ഞെടുപ്പിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"സ്ക്രീൻ വിഭജന മോഡിന് മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ദ്രുത ക്രമീകരണം"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ടാസ്ക്ബാർ"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ടാസ്ക്ബാർ കാണിച്ചിരിക്കുന്നു"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ടാസ്ക്ബാറും ബബിളും ഇടതുവശത്ത്"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ടാസ്ക്ബാറും ബബിളും വലതുവശത്ത്"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ടാസ്ക്ബാർ മറച്ചിരിക്കുന്നു"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ടാസ്ക്ബാറും ബബിളും മറച്ചു"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"നാവിഗേഷൻ ബാർ"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ടാസ്ക്ബാർ എപ്പോഴും കാണിക്കൂ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"നാവിഗേഷൻ മോഡ് മാറ്റുക"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index a76117a..18c66d7 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Апп хослуулалт хадгал"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Дэлгэцийг хуваахыг ашиглахын тулд өөр аппыг товш"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Дэлгэц хуваахыг ашиглахын тулд өөр апп сонгоно уу"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Цуцлах"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Цуцлах"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Дэлгэцийг хуваах сонголтоос гарах"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Дэлгэцийг хуваах горим ашиглах өөр апп сонгоно уу"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Шуурхай тохиргоо"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Ажлын хэсэг"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Ажлын хэсгийг харуулсан"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Ажлын хэсэг, бөмбөлгийг зүүн талд харуулсан"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Ажлын хэсэг, бөмбөлгийг баруун талд харуулсан"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Ажлын хэсгийг нуусан"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Ажлын хэсэг, бөмбөлгийг нуусан"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигацын самбар"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Ажлын хэсгийг үргэлж харуулах"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Навигацын горимыг өөрчлөх"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 09f40ab..45f768a 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ॲपची जोडी सेव्ह करा"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द करा"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"रद्द करा"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"स्प्लिट स्क्रीन निवडीतून बाहेर पडा"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"अॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"क्विक सेटिंग्ज"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"टास्कबार दाखवलेला आहे"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"टास्कबार आणि डावे बबल दाखवले"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"टास्कबार आणि उजवे बबल लपवले"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"टास्कबार लपवलेले आहे"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"टास्कबार आणि बबल लपवले आहेत"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेव्हिगेशन बार"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"नेहमी टास्कबार दाखवा"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"नेव्हिगेशन मोड बदला"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 72887ef..5d56cd1 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Simpan gandingan apl"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Ketik apl lain untuk menggunakan skrin pisah"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pilih apl lain untuk menggunakan skrin pisah"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Batal"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Batal"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Keluar daripada pilihan 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>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 749c1b5..06740db 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်အတွဲ သိမ်းရန်"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"မလုပ်တော့"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း ရွေးချယ်မှုမှ ထွက်ရန်"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"မျက်နှာပြင်ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"အမြန်ဆက်တင်များ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"လုပ်ဆောင်စရာဘား"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar ပြထားသည်"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ဘယ်ဘက်၌ Taskbar နှင့် ပူဖောင်းကွက် ပြထားသည်"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ညာဘက်၌ Taskbar နှင့် ပူဖောင်းကွက် ပြထားသည်"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar ဖျောက်ထားသည်"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taskbar နှင့် ပူဖောင်းကွက် ဖျောက်ထားသည်"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"လမ်းညွှန်ဘား"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Taskbar အမြဲပြရန်"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ရွှေ့ကြည့်သည့်မုဒ် ပြောင်းရန်"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 245945b..6a31efa 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Lagre apptilkobling"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Velg en annen app for å bruke delt skjerm"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Avslutt valg av 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hurtiginnst."</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Oppgavelinje"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Oppgavelinjen vises"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Venstre oppgavelinje/boble vises"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Høyre oppgavelinje/bobler vises"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Oppgavelinjen er skjult"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Oppgavelinje og bobler skjult"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasjonsrad"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Vis alltid oppgavelinjen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Endre navigasjonsmodus"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index f881637..b4a0136 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"एपको पेयर सेभ गर्नुहोस्"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिटस्क्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नु…"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द गर्नुहोस्"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"स्प्लिट स्क्रिन मोडबाट बाहिरिनुहोस्"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"द्रुत सेटिङ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"टास्कबार देखाइएको छ"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"टास्कबार र बबल बार बायाँतिर देखाइएका छन्"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"टास्कबार र बबल बार दायाँतिर देखाइएका छन्"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"टास्कबार लुकाइएको छ"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"टास्कबार र बबल बार लुकाइएका छन्"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेभिगेसन बार"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार सधैँ देखाउनुहोस्"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"नेभिगेसन मोड बदल्नुहोस्"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 09f8aca..0cd8141 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"App-paar opslaan"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tik op nog een app om je scherm te splitsen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Kies een andere app om gesplitst scherm te gebruiken"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuleren"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuleren"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Sluit de selectie voor gesplitst scherm"</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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Snelle instellingen"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taakbalk"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taakbalk wordt getoond"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taakbalk en bubbels links getoond"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taakbalk en bubbels rechts getoond"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taakbalk is verborgen"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Taakbalk en bubbels verborgen"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatiebalk"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Taakbalk altijd tonen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigatiemodus wijzigen"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 83522f3..97b0493 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ବାତିଲ କରନ୍ତୁ"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଚୟନରୁ ବାହାରି ଯାଆନ୍ତୁ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"କୁଇକ ସେଟିଂସ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ଟାସ୍କବାର"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ଟାସ୍କବାର ଦେଖାଯାଇଛି"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ଟାସ୍କବାର ଓ ବବଲ ବାମରେ ଦେଖାଯାଇଛି"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ଟାସ୍କବାର ଓ ବବଲ ଡାହାଣରେ ଦେଖାଯାଇଛି"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ଟାସ୍କବାର ଲୁଚାଯାଇଛି"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ଟାସ୍କବାର ଓ ବବଲ ଲୁଚାଯାଇଛି"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ନାଭିଗେସନ ବାର"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ସର୍ବଦା ଟାସ୍କବାର ଦେଖାନ୍ତୁ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ନାଭିଗେସନ ମୋଡ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 197fc6c..bd7e4d8 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ਰੱਦ ਕਰੋ"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਚੋਣ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ਟਾਸਕਬਾਰ"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ਟਾਸਕਬਾਰ ਨੂੰ ਦਿਖਾਇਆ ਗਿਆ"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ਟਾਸਕਬਾਰ ਤੇ ਬਬਲ ਨੂੰ ਖੱਬੇ ਦਿਖਾਇਆ"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ਟਾਸਕਬਾਰ ਤੇ ਬਬਲ ਨੂੰ ਸੱਜੇ ਦਿਖਾਇਆ"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ਟਾਸਕਬਾਰ ਨੂੰ ਲੁਕਾਇਆ ਗਿਆ"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ਟਾਸਕਬਾਰ ਅਤੇ ਬਬਲ ਨੂੰ ਲੁਕਾਇਆ ਗਿਆ"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ਨੈਵੀਗੇਸ਼ਨ ਵਾਲੀ ਪੱਟੀ"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਓ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ਨੈਵੀਗੇਸ਼ਨ ਮੋਡ ਬਦਲੋ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 5d6d927..942cdde 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Zapisz parę"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Aby podzielić ekran, kliknij drugą aplikację"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Aby podzielić ekran, wybierz drugą aplikację"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anuluj"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Anuluj"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Wyjdź z wyboru podzielonego ekranu"</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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Szybkie ustawienia"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Pasek aplikacji"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Pasek aplikacji widoczny"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Pasek i dymki po lewej"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Pasek i dymki po prawej"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Pasek aplikacji ukryty"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Pasek i dymki są ukryte"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Pasek nawigacyjny"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Zawsze pokazuj pasek aplikacji"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Zmień tryb nawigacji"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 4787ec3..50058c9 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Guardar par de apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toque noutra app para usar o ecrã dividido"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolha outra app para usar o ecrã dividido"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Saia da seleção de 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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Definiç. rápidas"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tarefas apresentada"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra de tarefas/balões à esq."</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra de tarefas/balões à dir."</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tarefas ocultada"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra tarefas/balões ocultos"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre Barra de tarefas"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Alterar modo de navegação"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index cb45f07..6ad7b2e 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computador"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Modo área de trabalho"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Remover tudo"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Salvar par de apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toque em outro app para usar a tela dividida"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolha outro app para usar na tela dividida"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Sair da seleção de 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. rápidas"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tarefas visível"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Barra de tar. e balões à esq."</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Barra de tar. e balões à dir."</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tarefas oculta"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Barra de tar. e balões ocultos"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Sempre mostrar a Barra de tarefas"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Mudar o modo de navegação"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 31b1951..9b264b8 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixează"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formă liberă"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computer"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
<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>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Salvează perechea de aplicații"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Atinge altă aplicație pentru ecranul împărțit"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Alege altă aplicație pentru a folosi ecranul împărțit"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulează"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ieși din selecția cu ecran î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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Setări rapide"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Bară de activități"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Bara de activități este afișată"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Bară și baloane stânga afișate"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Bară & baloane dreapta afișate"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Bara de activități este ascunsă"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Bară și baloane ascunse"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bară de navigare"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Afișează mereu bara"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Schimbă modul de navigare"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 72559f6..5bcae00 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закрепить"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Произвольная форма"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"Включить режим для ПК"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Мультиоконный режим"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
@@ -72,7 +72,7 @@
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"У вас получилось!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Проведите снизу вверх от самого края экрана."</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Прежде чем отпустить палец, задержите его на экране немного дольше."</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Проведите по экрану ровно вверх и задержите палец в конце."</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Проведите по экрану вверх и задержите палец."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Теперь вы знаете, как использовать жесты. Чтобы отключить их, перейдите в настройки."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Вы выполнили жест для переключения между приложениями."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Переключение между приложениями"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Сохранить приложения"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Чтобы использовать разделенный экран, выберите другое приложение."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отмена"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Выйдите из режима разделения экрана."</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Выберите другое приложение для разделения экрана."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Это действие заблокировано приложением или организацией."</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Быстрые настройки"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Панель задач"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Панель задач показана"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Слева панель задач, подсказки"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Справа панель задач, подсказки"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Панель задач скрыта"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Скрыты панель задач, подсказки"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навигации"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Всегда показывать панель задач"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Изменить режим навигации"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 6e7aabb..b23617f 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"යෙදුම් යුගල සුරකින්න"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"බෙදුම් තිරය භාවිතා කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"බෙදුම් තිරය භාවිත කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"අවලංගු කරන්න"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"බෙදීම් තිර තේරීමෙන් පිටවන්න"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"බෙදීම් තිරය භාවිතා කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"ඉක්මන් සැකසීම්"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"කාර්ය තීරුව"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"කාර්ය තීරුව පෙන්වා ඇත"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"කාර්ය තීරුව සහ බුබුළු පෙන්වා ඇත"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"කාර්ය තීරුව සහ බුබුළු දකුණට පෙන්වා ඇත"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"කාර්ය තීරුව සඟවා ඇත"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"කාර්ය තීරුව සහ බුබුළු සඟවා ඇත"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"සංචලන තීරුව"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"සෑම විටම කාර්ය තීරුව පෙන්වන්න"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"සංචාලන ප්රකාරය වෙනස් කරන්න"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 5fbe4f1..278ad0e 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -90,7 +90,7 @@
<string name="allset_title" msgid="5021126669778966707">"Hotovo"</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="allset_description_generic" msgid="5385500062202019855">"Môžete <xliff:g id="DEVICE">%1$s</xliff:g> začať používať"</string>
<string name="default_device_name" msgid="6660656727127422487">"zariadenie"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavenia navigácie systémom"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Uložiť pár aplikácií"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdelíte klepnutím na inú aplikáciu"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Na použitie rozdelenej obrazovky vyberte ďalšiu aplikáciu"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušiť"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ukončite výber rozdelenej obrazovky"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rýchle nastavenia"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Panel aplikácií"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Panel aplikácií je zobrazený"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Panel aplik. a bubl. sú vľavo"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Panel aplik. a bubl. sú vpravo"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Panel aplikácií je skrytý"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Panel aplik. a bubl. sú skryté"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigačný panel"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Zobrazovať panel aplikácií"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Zmeniť režim navigácie"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 62c0c3c..0c201b4 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Shrani par aplikacij"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Za razdeljeni zaslon se dotaknite še 1 aplikacije"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Izberite drugo aplikacijo za uporabo razdeljenega zaslona."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Prekliči"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Prekliči"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Zapri izbiro razdeljenega zaslona"</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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hitre nastavitve"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Opravilna vrstica"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Opravilna vrstica je prikazana"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Prikazani so opravilna vrstica in oblački na levi"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Prikazani so opravilna vrstica in oblački na desni"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Opravilna vrstica je skrita"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Opravilna vrstica in oblački so skriti"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Vrstica za krmarjenje"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Stalen prikaz oprav. vrstice"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Spreminjanje načina navigacije"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 78f2733..cd5725d 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Ruaj çiftin e aplikacioneve"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Trokit një apl. tjetër; përdor ekranin e ndarë"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulo"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Dil nga zgjedhja e ekranit të 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cilësimet shpejt"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Shiriti i detyrave"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Shiriti i detyrave i shfaqur"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Shiriti i detyrave dhe flluskat majtas janë shfaqur"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Shiriti i detyrave dhe flluskat djathtas janë shfaqur"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Shiriti i detyrave i fshehur"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Shiriti i detyrave dhe flluskat janë fshehur"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Shiriti i navigimit"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Shfaq gjithmonë shiritin e detyrave"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Ndrysho modalitetin e navigimit"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index ee3a467..708406b 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Сачувај пар апликација"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Одаберите другу апликацију да бисте користили подељени екран"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Излазак из бирања подељеног екрана"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брза подешавања"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Трака задатака"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Трака задатака је приказана"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Приказ задатака/облачића лево"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Приказ задатака/облачића десно"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Трака задатака је скривена"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Скривени задаци/облачићи"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Трака за навигацију"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Увек приказуј траку задатака"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Промени режим навигације"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index e2cf71f..ef0ef76 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Spara app-par"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Välj en annan app för att använda delad skärm"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Avsluta val av 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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Snabbinställn."</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Aktivitetsfält"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Aktivitetsfältet visas"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Vänster fält och bubblor visas"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Höger fält och bubblor visas"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Aktivitetsfältet är dolt"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Fält och bubblor dolda"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeringsfält"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Visa alltid aktivitetsfältet"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Ändra navigeringsläge"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 66feb58..63b5922 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Hifadhi jozi ya programu"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Gusa programu nyingine ili utumie kipengele cha kugawa skrini"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ghairi"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ondoka kwenye hali ya skrini iliyogawanywa"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Mipangilio ya Haraka"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Upauzana"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Upauzana umeonyeshwa"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Upauzana na viputo vinaonyeshwa kushoto"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Upauzana na viputo vinaonyeshwa kulia"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Upauzana umefichwa"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Upauzana na viputo vimefichwa"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Sehemu ya viungo muhimu"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Onyesha Zana kila wakati"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Badilisha hali ya usogezaji"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 43e12ee..5159245 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -90,7 +90,7 @@
<string name="allset_title" msgid="5021126669778966707">"அனைத்தையும் அமைத்துவிட்டீர்கள்!"</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="allset_description_generic" msgid="5385500062202019855">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> ஐப் பயன்படுத்தத் தயாராகிவிட்டீர்கள்"</string>
<string name="default_device_name" msgid="6660656727127422487">"சாதனம்"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"சிஸ்டம் வழிசெலுத்தல் அமைப்புகள்"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"பகிர்"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தட்டவும்"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தேர்வுசெய்யுங்கள்"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ரத்துசெய்"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"திரைப் பிரிப்பு தேர்வில் இருந்து வெளியேறும்"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"திரைப் பிரிப்பை பயன்படுத்த வேறு ஆப்ஸை தேர்வுசெய்க"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"விரைவு அமைப்புகள்"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"செயல் பட்டி"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"செயல் பட்டி காட்டப்படுகிறது"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"செயல் பட்டி & குமிழை இடதுபுறம் காட்டும்"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"செயல் பட்டி & குமிழை வலதுபுறம் காட்டும்"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"செயல் பட்டி மறைக்கப்பட்டுள்ளது"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"செயல் பட்டி & குமிழை மறைக்கும்"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"வழிசெலுத்தல் பட்டி"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"செயல் பட்டியை எப்போதும் காட்டு"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"வழிசெலுத்தல் பயன்முறையை மாற்று"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index fbe67dc..8c8e688 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"యాప్ పెయిర్ను సేవ్ చేయండి"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్ను ట్యాప్ చేయండి"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"స్ప్లిట్ స్క్రీన్ను ఉపయోగించడానికి మరొక యాప్ ఎంచుకోండి"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"రద్దు చేయండి"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"రద్దు చేయండి"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"స్ప్లిట్ స్క్రీన్ ఎంపిక నుండి ఎగ్జిట్ అవ్వండి"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"స్ప్లిట్ స్క్రీన్ ఉపయోగానికి మరొక యాప్ ఎంచుకోండి"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ఈ చర్యను యాప్ గానీ, మీ సంస్థ గానీ అనుమతించవు"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 7816628..2c5f9a6 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"บันทึกคู่แอป"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"แตะแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"เลือกแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ยกเลิก"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"ยกเลิก"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ออกจากการเลือกโหมดแยกหน้าจอ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"เลือกแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"การตั้งค่าด่วน"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"แถบงาน"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"แถบงานแสดงอยู่"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"แถบงานและบับเบิลแสดงไว้ทางซ้าย"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"แถบงานและบับเบิลแสดงไว้ทางขวา"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"แถบงานซ่อนอยู่"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"แถบงานและบับเบิลซ่อนอยู่"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"แถบนำทาง"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"แสดงแถบงานเสมอ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"เปลี่ยนโหมดการนําทาง"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index e1a77a5..88ebb4a 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"I-save ang app pair"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Mag-tap ng ibang app para gamitin ang split screen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pumili ng ibang app para gamitin ang split screen"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Kanselahin"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Kanselahin"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Lumabas sa pagpili ng 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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Ipinapakita ang taskbar"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Taskbar at bubble sa kaliwa"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Taskbar at bubble sa kanan"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Nakatago ang taskbar"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Nakatago ang taskbar at bubble"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Ipakita lagi ang Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Magpalit ng navigation mode"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index ef8f50d..6117bfd 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -90,7 +90,7 @@
<string name="allset_title" msgid="5021126669778966707">"İşlem tamam!"</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="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> adlı cihazınızı kullanmaya hazırsınız"</string>
<string name="default_device_name" msgid="6660656727127422487">"cihaz"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sistem gezinme ayarları"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Paylaş"</string>
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Uygulama çiftini kaydet"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"İptal"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"İptal"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Bölünmüş ekran seçiminden çıkın"</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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hızlı Ayarlar"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Görev çubuğu."</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Görev çubuğu gösteriliyor"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Görev çubuğu ve baloncuklar solda gösteriliyor"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Görev çubuğu ve baloncuklar sağda gösteriliyor"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Görev çubuğu gizlendi"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Görev çubuğu ve baloncuklar gizli"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Gezinme çubuğu"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Görev çubuğunu daima göster"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Gezinme modunu değiştir"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 201ac18..44170e9 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закріпити"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Довільна форма"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"Комп’ютер"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Робочий стіл"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налаштування використання додатка"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистити все"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Зберегти пару"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Щоб розділити екран, виберіть ще один додаток."</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасувати"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Вийти з режиму розділення екрана"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Швидкі налаштув."</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Панель завдань"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Панель завдань показано"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Панель завдань і чати – зліва"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Панель завдань і чати – справа"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Панель завдань приховано"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Панель і чати приховано"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навігації"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Завжди показув. панель завдань"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Змінити режим навігації"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index b2a5c88..89cfbbb 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"ایپس کے جوڑے کو محفوظ کریں"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"منسوخ کریں"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"اسپلٹ اسکرین کے انتخاب سے باہر نکلیں"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"فوری ترتیبات"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ٹاسک بار"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ٹاشک بار دکھایا گیا"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ٹاسک بار و بلبلے بائیں طرف ہیں"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ٹاسک بار و بلبلے دائیں طرف ہیں"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ٹاسک بار چھپایا گیا"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ٹاسک بار اور بلبلے پوشیدہ ہیں"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نیویگیشن بار"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"ہمیشہ ٹاسک بار دکھائیں"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"نیویگیشن موڈ تبدیل کریں"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 6df0b31..e3c7727 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Ilova juftini saqlash"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Ekranni ikkiga ajratish uchun boshqa ilovani bosing"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Ekranni ikkiga ajratish uchun boshqa ilovani tanlang"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Bekor qilish"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Bekor qilish"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ekranni ikkiga ajratish tanlovidan chiqish"</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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Tezkor sozlamalar"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Vazifalar paneli"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Vazifalar paneli ochiq"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Panel va bulutchalar chapda"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Panel va bulutchalar oʻngda"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Vazifalar paneli yopiq"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Panel va bulutchalar berk"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatsiya paneli"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Vazifalar paneli doim chiqarilsin"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigatsiya rejimini oʻzgartirish"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 76eec0c..8844fe9 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Lưu cặp ứng dụng"</string>
<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_contextual_split_select_app" msgid="433510957123687090">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Huỷ"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Huỷ"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Thoát khỏi lựa chọn 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>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cài đặt nhanh"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Thanh tác vụ"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Đã hiện thanh thao tác"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"Hiện thanh tác vụ, b.bóng trái"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"Hiện thanh tác vụ, b.bóng phải"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Đã ẩn thanh thao tác"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"Đã ẩn thanh tác vụ & bong bóng"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Thanh điều hướng"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Luôn hiện Thanh tác vụ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Thay đổi chế độ điều hướng"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b5ae26d..b52d33b 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由窗口"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面设备"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"应用使用设置"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"保存应用组合"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"点按另一个应用即可使用分屏"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"另外选择一个应用才可使用分屏模式"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分屏选择模式"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"另外选择一个应用才可使用分屏模式"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"该应用或您所在的单位不允许执行此操作"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"快捷设置"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"任务栏"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"任务栏已显示"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"已显示任务栏和左侧消息气泡"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"已显示任务栏和右侧消息气泡"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"任务栏已隐藏"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"已隐藏任务栏和消息气泡"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"导航栏"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"始终显示任务栏"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"更改导航模式"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index dd52065..a048848 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -99,7 +99,7 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"儲存應用程式組合"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"輕按其他應用程式以使用分割螢幕"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"選擇其他應用程式才能使用分割螢幕"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"取消"</string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分割螢幕選取頁面"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"選擇其他應用程式才能使用分割螢幕"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"應用程式或你的機構不允許此操作"</string>
@@ -130,13 +130,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"工作列"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"顯示咗工作列"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"工作列和對話氣泡在左邊顯示"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"工作列和對話氣泡在右邊顯示"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"隱藏咗工作列"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"工作列和對話氣泡已隱藏"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"一律顯示工作列"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"變更導覽模式"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 6d7652a..a27f2c5 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"電腦"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"儲存應用程式配對"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"輕觸另一個應用程式即可使用分割畫面"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"選擇要在分割畫面中使用的另一個應用程式"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分割畫面選擇器"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"必須選擇另一個應用程式才能使用分割畫面"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"這個應用程式或貴機構不允許執行這個動作"</string>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"工作列"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"已顯示工作列"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"工作列和對話框顯示在左側"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"工作列和對話框顯示在右側"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"已隱藏工作列"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"已隱藏工作列和對話框"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"一律顯示工作列"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"變更操作模式"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 973ce80..b5f6abc 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -99,7 +99,8 @@
<string name="action_save_app_pair" msgid="5974823919237645229">"Londoloza ukubhangqa i-app"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string>
- <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Khansela"</b></string>
+ <!-- no translation found for toast_split_select_app_cancel (1939025102486630426) -->
+ <skip />
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Phuma ekukhetheni ukuhlukaniswa kwesikrini"</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>
@@ -130,13 +131,10 @@
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Amasethingi Asheshayo"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"I-Taskbar"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Ibha yomsebenzi ibonisiwe"</string>
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_left_title (4242431789851790046) -->
- <skip />
- <!-- no translation found for taskbar_a11y_shown_with_bubbles_right_title (8219065376188180113) -->
- <skip />
+ <string name="taskbar_a11y_shown_with_bubbles_left_title" msgid="4242431789851790046">"ITaskbar namabhamuza aboniswe kwesokunxele"</string>
+ <string name="taskbar_a11y_shown_with_bubbles_right_title" msgid="8219065376188180113">"ITaskbar namabhamuza aboniswe kwesokudla"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Ibha yomsebenzi ifihliwe"</string>
- <!-- no translation found for taskbar_a11y_hidden_with_bubbles_title (7397395993149508087) -->
- <skip />
+ <string name="taskbar_a11y_hidden_with_bubbles_title" msgid="7397395993149508087">"ITaskbar namabhamuza afihliwe"</string>
<string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Ibha yokufuna"</string>
<string name="always_show_taskbar" msgid="3608801276107751229">"Bonisa i-Taskbar njalo."</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Shintsha imodi yokufuna"</string>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index fd12210..e8cb5d5 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -35,7 +35,7 @@
<string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
<string name="plugin_manager_wrapper_class" translatable="false">com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl</string>
<string name="taskbar_edu_tooltip_controller_class" translatable="false">com.android.launcher3.taskbar.TaskbarEduTooltipController</string>
-
+ <string name="contextual_edu_manager_class" translatable="false">com.android.quickstep.contextualeducation.SystemContextualEduStatsManager</string>
<string name="nav_handle_long_press_handler_class" translatable="false"></string>
<string name="assist_utils_class" translatable="false"></string>
<string name="assist_state_manager_class" translatable="false"></string>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 8bcbb33..d0f474f 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -26,9 +26,12 @@
<string name="recent_task_option_pin">Pin</string>
<!-- Title for an option to enter freeform mode for a given app -->
<string name="recent_task_option_freeform">Freeform</string>
- <!-- Title for an option to enter desktop windowing mode for a given app -->
+ <!-- Title and content description for an option to enter desktop windowing mode for a given app -->
<string name="recent_task_option_desktop">Desktop</string>
+ <!-- Title and content description for Desktop tile in Recents screen that contains apps opened inside desktop windowing mode [CHAR LIMIT=NONE] -->
+ <string name="recent_task_desktop">Desktop</string>
+
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">No recent items</string>
@@ -237,7 +240,7 @@
<!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
<string name="toast_split_select_app">Tap another app to use split screen</string>
<string name="toast_contextual_split_select_app">Choose another app to use split screen</string>
- <string name="toast_split_select_app_cancel"><b>Cancel</b></string>
+ <string name="toast_split_select_app_cancel">Cancel</string>
<string name="toast_split_select_cont_desc">Exit split screen selection</string>
<!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
<string name="toast_split_app_unsupported">Choose another app to use split screen</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index fe1b403..4a1035f 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -356,14 +356,6 @@
options.setOnAnimationAbortListener(endCallback);
options.setOnAnimationFinishedListener(endCallback);
- // Prepare taskbar for animation synchronization. This needs to happen here before any
- // app transition is created.
- LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
- if (enableScalingRevealHomeAnimation() && taskbarController != null) {
- taskbarController.setIgnoreInAppFlagForSync(true);
- onEndCallback.add(() -> taskbarController.setIgnoreInAppFlagForSync(false));
- }
-
IBinder cookie = mAppLaunchRunner.supportsReturnTransition()
? ((ContainerAnimationRunner) mAppLaunchRunner).getCookie() : null;
addLaunchCookie(cookie, (ItemInfo) v.getTag(), options);
@@ -1942,21 +1934,6 @@
anim.addListener(mForceInvisibleListener);
}
- // Syncs the app launch animation and taskbar stash animation (if exists).
- if (enableScalingRevealHomeAnimation()) {
- LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
- if (taskbarController != null) {
- taskbarController.setIgnoreInAppFlagForSync(false);
-
- if (launcherClosing) {
- Animator taskbar = taskbarController.createAnimToApp();
- if (taskbar != null) {
- anim.play(taskbar);
- }
- }
- }
- }
-
result.setAnimation(anim, mLauncher, mOnEndCallback::executeAllAndDestroy,
skipFirstFrame);
}
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 9178062..189deda 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -44,11 +44,13 @@
/** Launch desktop tasks from recents view */
fun launchDesktopFromRecents(
desktopTaskView: DesktopTaskView,
+ animated: Boolean,
callback: Consumer<Boolean>? = null
) {
val animRunner =
RemoteDesktopLaunchTransitionRunner(
desktopTaskView,
+ animated,
stateManager,
depthController,
callback
@@ -64,6 +66,7 @@
private class RemoteDesktopLaunchTransitionRunner(
private val desktopTaskView: DesktopTaskView,
+ private val animated: Boolean,
private val stateManager: StateManager<*, *>,
private val depthController: DepthController?,
private val successCallback: Consumer<Boolean>?
@@ -84,16 +87,21 @@
}
MAIN_EXECUTOR.execute {
- TaskViewUtils.composeRecentsDesktopLaunchAnimator(
- desktopTaskView,
- stateManager,
- depthController,
- info,
- t
- ) {
- errorHandlingFinishCallback.run()
- successCallback?.accept(true)
+ val animator =
+ TaskViewUtils.composeRecentsDesktopLaunchAnimator(
+ desktopTaskView,
+ stateManager,
+ depthController,
+ info,
+ t
+ ) {
+ errorHandlingFinishCallback.run()
+ successCallback?.accept(true)
+ }
+ if (!animated) {
+ animator.setDuration(0)
}
+ animator.start()
}
}
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 6c7fe5b..644705b 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -25,6 +25,7 @@
import android.util.Log;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
@@ -38,6 +39,7 @@
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.Executor;
/**
* Controls the visibility of the workspace and the resumed / paused state when desktop mode
@@ -56,7 +58,7 @@
private boolean mGestureInProgress;
@Nullable
- private IDesktopTaskListener mDesktopTaskListener;
+ private DesktopTaskListenerImpl mDesktopTaskListener;
public DesktopVisibilityController(Launcher launcher) {
mLauncher = launcher;
@@ -66,24 +68,7 @@
* Register a listener with System UI to receive updates about desktop tasks state
*/
public void registerSystemUiListener() {
- mDesktopTaskListener = new IDesktopTaskListener.Stub() {
- @Override
- public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
- MAIN_EXECUTOR.execute(() -> {
- if (displayId == mLauncher.getDisplayId()) {
- if (DEBUG) {
- Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
- }
- setVisibleDesktopTasksCount(visibleTasksCount);
- }
- });
- }
-
- @Override
- public void onStashedChanged(int displayId, boolean stashed) {
- Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
- }
- };
+ mDesktopTaskListener = new DesktopTaskListenerImpl(this, mLauncher.getDisplayId());
SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(mDesktopTaskListener);
}
@@ -92,6 +77,7 @@
*/
public void unregisterSystemUiListener() {
SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(null);
+ mDesktopTaskListener.release();
mDesktopTaskListener = null;
}
@@ -355,4 +341,43 @@
*/
void onDesktopVisibilityChanged(boolean visible);
}
+
+ /**
+ * Wrapper for the IDesktopTaskListener stub to prevent lingering references to the launcher
+ * activity via the controller.
+ */
+ private static class DesktopTaskListenerImpl extends IDesktopTaskListener.Stub {
+
+ private DesktopVisibilityController mController;
+ private final int mDisplayId;
+
+ DesktopTaskListenerImpl(@NonNull DesktopVisibilityController controller, int displayId) {
+ mController = controller;
+ mDisplayId = displayId;
+ }
+
+ /**
+ * Clears any references to the controller.
+ */
+ void release() {
+ mController = null;
+ }
+
+ @Override
+ public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
+ MAIN_EXECUTOR.execute(() -> {
+ if (mController != null && displayId == mDisplayId) {
+ if (DEBUG) {
+ Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
+ }
+ mController.setVisibleDesktopTasksCount(visibleTasksCount);
+ }
+ });
+ }
+
+ @Override
+ public void onStashedChanged(int displayId, boolean stashed) {
+ Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
index c201236..a833ccf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
@@ -16,19 +16,24 @@
package com.android.launcher3.taskbar;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.SystemUiProxy;
import java.util.ArrayList;
import java.util.List;
// TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar.
/** Base for common behavior between taskbar window contexts. */
-public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext {
+public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext,
+ SystemShortcut.BubbleActivityStarter {
protected final LayoutInflater mLayoutInflater;
private final List<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
@@ -48,6 +53,18 @@
return mDPChangeListeners;
}
+ @Override
+ public void showShortcutBubble(ShortcutInfo info) {
+ if (info == null) return;
+ SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info);
+ }
+
+ @Override
+ public void showAppBubble(Intent intent) {
+ if (intent == null || intent.getPackage() == null) return;
+ SystemUiProxy.INSTANCE.get(this).showAppBubble(intent);
+ }
+
/** Callback invoked when a drag is initiated within this context. */
public abstract void onDragStart();
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 0ba5de1..dbd9c73 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -54,6 +54,7 @@
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.HashMap;
@@ -213,9 +214,16 @@
resources.getString(R.string.quick_switch_desktop),
Locale.getDefault()).format(args));
} else {
+ final boolean firstTaskIsLeftTopTask =
+ groupTask.mSplitBounds == null
+ || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
+ final Task leftTopTask = firstTaskIsLeftTopTask
+ ? groupTask.task1 : groupTask.task2;
+ final Task rightBottomTask = firstTaskIsLeftTopTask
+ ? groupTask.task2 : groupTask.task1;
currentTaskView.setThumbnails(
- groupTask.task1,
- groupTask.task2,
+ leftTopTask,
+ rightBottomTask,
updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
updateTasks ? mViewCallbacks::updateIconInBackground : null);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 3981e43..8df2eb8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
-import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IGNORE_IN_APP;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
@@ -225,9 +224,12 @@
// Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
// avoid updating taskbar state in that situation (when it's non-interactive -- or
// "background") to avoid premature animations.
- if (ENABLE_SHELL_TRANSITIONS && isVisible
- && mLauncher.getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE)
- && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) {
+ LauncherState state = mLauncher.getStateManager().getState();
+ boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
+ && !state.isTaskbarAlignedWithHotseat(mLauncher);
+ if ((ENABLE_SHELL_TRANSITIONS
+ && isVisible
+ && (nonInteractiveState || mSkipLauncherVisibilityChange))) {
return null;
}
@@ -276,28 +278,6 @@
return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
}
- /**
- * Create Taskbar animation to be played alongside the Launcher app launch animation.
- */
- public @Nullable Animator createAnimToApp() {
- TaskbarStashController stashController = mControllers.taskbarStashController;
- stashController.updateStateForFlag(TaskbarStashController.FLAG_IN_APP, true);
- return stashController.createApplyStateAnimator(stashController.getStashDuration());
- }
-
- /**
- * Temporarily ignore FLAG_IN_APP for app launches to prevent premature taskbar stashing.
- * This is needed because taskbar gets a signal to stash before we actually start the
- * app launch animation.
- */
- public void setIgnoreInAppFlagForSync(boolean enabled) {
- if (mControllers == null) {
- // This method can be called before init() is called.
- return;
- }
- mControllers.taskbarStashController.updateStateForFlag(FLAG_IGNORE_IN_APP, enabled);
- }
-
public void updateTaskbarLauncherStateGoingHome() {
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, true);
mTaskbarLauncherStateController.applyState();
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index ea2adcf..f61840a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -264,11 +264,19 @@
boolean isThreeButtonNav = mContext.isThreeButtonNav();
DeviceProfile deviceProfile = mContext.getDeviceProfile();
Resources resources = mContext.getResources();
- Point p = !mContext.isUserSetupComplete()
- ? new Point(0, mControllers.taskbarActivityContext.getSetupWindowSize())
- : DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
- mContext.isPhoneMode());
- mNavButtonsView.getLayoutParams().height = p.y;
+
+ int setupSize = mControllers.taskbarActivityContext.getSetupWindowSize();
+ Point p = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
+ mContext.isPhoneMode(), mContext.isGestureNav());
+ ViewGroup.LayoutParams navButtonsViewLayoutParams = mNavButtonsView.getLayoutParams();
+ navButtonsViewLayoutParams.width = p.x;
+ if (!mContext.isUserSetupComplete()) {
+ // Setup mode in phone mode uses gesture nav.
+ navButtonsViewLayoutParams.height = setupSize;
+ } else {
+ navButtonsViewLayoutParams.height = p.y;
+ }
+ mNavButtonsView.setLayoutParams(navButtonsViewLayoutParams);
mIsImeRenderingNavButtons =
InputMethodService.canImeRenderGesturalNavButtons() && mContext.imeDrawsImeNavBar();
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 266d0b9..475b516 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -212,7 +212,7 @@
* stashed handle to wrap around the hotseat items.
*/
public Animator createRevealAnimToIsStashed(boolean isStashed, Rect taskbarToHotseatOffsets) {
- Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
+ Rect visualBounds = mControllers.taskbarViewController.getIconLayoutVisualBounds();
float startRadius = mStashedHandleRadius;
if (DisplayController.isTransientTaskbar(mActivity)) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index f579d86..cd1eea2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -25,6 +25,7 @@
import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
import static com.android.launcher3.Flags.enableCursorHoverStates;
@@ -108,11 +109,16 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleCreator;
import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
import com.android.launcher3.taskbar.bubbles.BubbleDragController;
import com.android.launcher3.taskbar.bubbles.BubblePinController;
-import com.android.launcher3.taskbar.bubbles.BubbleStashController;
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider;
+import com.android.launcher3.taskbar.bubbles.stashing.DeviceProfileDimensionsProviderAdapter;
+import com.android.launcher3.taskbar.bubbles.stashing.PersistentBubbleStashController;
+import com.android.launcher3.taskbar.bubbles.stashing.TransientBubbleStashController;
import com.android.launcher3.taskbar.customization.TaskbarFeatureEvaluator;
import com.android.launcher3.taskbar.customization.TaskbarSpecsEvaluator;
import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
@@ -141,6 +147,7 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
+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.Task;
@@ -150,6 +157,7 @@
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.systemui.unfold.updates.RotationChangeProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
+import com.android.wm.shell.Flags;
import java.io.PrintWriter;
import java.util.Collections;
@@ -250,15 +258,18 @@
mWindowManager = c.getSystemService(WindowManager.class);
// Inflate views.
- int taskbarLayout = DisplayController.isTransientTaskbar(this) && !isPhoneMode()
- ? R.layout.transient_taskbar
- : R.layout.taskbar;
+ final boolean isTransientTaskbar = DisplayController.isTransientTaskbar(this)
+ && !isPhoneMode();
+ int taskbarLayout = isTransientTaskbar ? R.layout.transient_taskbar : R.layout.taskbar;
mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
NearestTouchFrame navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
- BubbleBarView bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
+ BubbleBarView bubbleBarView = null;
+ if (isTransientTaskbar || Flags.enableBubbleBarInPersistentTaskBar()) {
+ bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
+ }
StashedHandleView bubbleHandleView = mDragLayer.findViewById(R.id.stashed_bubble_handle);
mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
@@ -267,17 +278,28 @@
Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
BubbleBarController.onTaskbarRecreated();
if (BubbleBarController.isBubbleBarEnabled() && bubbleBarView != null) {
+ Optional<BubbleStashedHandleViewController> bubbleHandleController = Optional.empty();
+ if (isTransientTaskbar) {
+ bubbleHandleController = Optional.of(
+ new BubbleStashedHandleViewController(this, bubbleHandleView));
+ }
+ TaskbarHotseatDimensionsProvider dimensionsProvider =
+ new DeviceProfileDimensionsProviderAdapter(this);
+ BubbleStashController bubbleStashController = isTransientTaskbar
+ ? new TransientBubbleStashController(dimensionsProvider, getResources())
+ : new PersistentBubbleStashController(dimensionsProvider);
bubbleControllersOptional = Optional.of(new BubbleControllers(
new BubbleBarController(this, bubbleBarView),
new BubbleBarViewController(this, bubbleBarView),
- new BubbleStashController(this),
- new BubbleStashedHandleViewController(this, bubbleHandleView),
+ bubbleStashController,
+ bubbleHandleController,
new BubbleDragController(this),
new BubbleDismissController(this, mDragLayer),
new BubbleBarPinController(this, mDragLayer,
() -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
new BubblePinController(this, mDragLayer,
- () -> DisplayController.INSTANCE.get(this).getInfo().currentSize)
+ () -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
+ new BubbleCreator(this)
));
}
@@ -906,7 +928,7 @@
mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
boolean isShadeVisible = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
- onNotificationShadeExpandChanged(isShadeVisible, fromInit);
+ onNotificationShadeExpandChanged(isShadeVisible, fromInit || isPhoneMode());
mControllers.taskbarViewController.setRecentsButtonDisabled(
mControllers.navbarButtonsViewController.isRecentsDisabled()
|| isNavBarKidsModeActive());
@@ -925,8 +947,9 @@
mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags);
mControllers.bubbleControllers.ifPresent(controllers -> {
controllers.bubbleBarController.updateStateForSysuiFlags(systemUiStateFlags);
- controllers.bubbleStashedHandleViewController.setIsHomeButtonDisabled(
- mControllers.navbarButtonsViewController.isHomeDisabled());
+ controllers.bubbleStashedHandleViewController.ifPresent(controller ->
+ controller.setIsHomeButtonDisabled(
+ mControllers.navbarButtonsViewController.isHomeDisabled()));
});
}
@@ -964,6 +987,7 @@
public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
mControllers.navbarButtonsViewController.onTransitionModeUpdated(barMode, checkBarModes);
}
+
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
.updateValue(darkIntensity);
@@ -1113,6 +1137,9 @@
* window.
*/
public void setTaskbarWindowFocusable(boolean focusable) {
+ if (isPhoneMode()) {
+ return;
+ }
if (focusable) {
mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
} else {
@@ -1125,7 +1152,7 @@
* Applies forcibly show flag to taskbar window iff transient taskbar is unstashed.
*/
public void applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow) {
- if (!DisplayController.isTransientTaskbar(this)) {
+ if (!DisplayController.isTransientTaskbar(this) || isPhoneMode()) {
return;
}
if (shouldForceShow) {
@@ -1392,7 +1419,8 @@
if (foundTask != null) {
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
if (foundTaskView != null
- && foundTaskView.isVisibleToUser()) {
+ && foundTaskView.isVisibleToUser()
+ && !(foundTaskView instanceof DesktopTaskView)) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
foundTaskView.launchTasks();
@@ -1443,7 +1471,6 @@
return;
}
}
-
startActivity(intent);
} else {
getSystemService(LauncherApps.class).startMainActivity(
@@ -1488,6 +1515,12 @@
itemView.setHapticFeedbackEnabled(true);
return false;
});
+
+ // Close any open taskbar tooltips.
+ if (AbstractFloatingView.hasOpenView(this, TYPE_ON_BOARD_POPUP)) {
+ AbstractFloatingView.getOpenView(this, TYPE_ON_BOARD_POPUP)
+ .close(/* animate= */ false);
+ }
});
}
@@ -1668,7 +1701,7 @@
* @param exclude {@code true} then the magnification region computation will omit the window.
*/
public void excludeFromMagnificationRegion(boolean exclude) {
- if (mIsExcludeFromMagnificationRegion == exclude) {
+ if (mIsExcludeFromMagnificationRegion == exclude || isPhoneMode()) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 0645972..d94d9175 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -165,6 +165,7 @@
taskbarOverlayController.init(this);
taskbarAllAppsController.init(this, sharedState.allAppsVisible);
navButtonController.init(this);
+ bubbleControllers.ifPresent(controllers -> controllers.init(this));
taskbarInsetsController.init(this);
voiceInteractionWindowController.init(this);
taskbarRecentAppsController.init(this);
@@ -172,7 +173,6 @@
taskbarEduTooltipController.init(this);
keyboardQuickSwitchController.init(this);
taskbarPinningController.init(this, mSharedState);
- bubbleControllers.ifPresent(controllers -> controllers.init(this));
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index ff890fb..acf976f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -291,7 +291,7 @@
if (mActivity.isPhoneMode()) {
Resources resources = mActivity.getResources();
Point taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile,
- resources, true /* isPhoneMode */);
+ resources, true /* isPhoneMode */, mActivity.isGestureNav());
return taskbarDimensions.y == -1 ?
deviceProfile.getDisplayInfo().currentSize.y :
taskbarDimensions.y;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index 6ac862e..8a86402 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -85,6 +85,9 @@
/** Update values tracked via sysui flags. */
public void updateSysuiFlags(@SystemUiStateFlags long sysuiFlags) {
+ if (mContext.isPhoneMode()) {
+ return;
+ }
mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) == 0;
if (mContext.isNavBarForceVisible()) {
if (mIsImmersiveMode) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
index dd14109..8c7879d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
@@ -18,30 +18,22 @@
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
import static android.view.MotionEvent.ACTION_HOVER_EXIT;
import static android.view.View.ALPHA;
-import static android.view.View.SCALE_Y;
-import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT;
-import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_EXCEPT_ON_BOARD_POPUP;
+import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS;
-import static com.android.launcher3.views.ArrowTipView.TEXT_ALPHA;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
import android.view.ContextThemeWrapper;
import android.view.MotionEvent;
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.apppairs.AppPairIcon;
-import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.views.ArrowTipView;
@@ -49,13 +41,9 @@
* Controls showing a tooltip in the taskbar above each icon when it is hovered.
*/
public class TaskbarHoverToolTipController implements View.OnHoverListener {
-
- private static final int HOVER_TOOL_TIP_REVEAL_DURATION = 250;
- private static final int HOVER_TOOL_TIP_EXIT_DURATION = 150;
-
- private final Handler mHoverToolTipHandler = new Handler(Looper.getMainLooper());
- private final Runnable mRevealHoverToolTipRunnable = this::revealHoverToolTip;
- private final Runnable mHideHoverToolTipRunnable = this::hideHoverToolTip;
+ // Short duration to reveal tooltip, as it is positioned in the x/y via a post() call in
+ // parallel with the open animation. An instant animation could show in the wrong location.
+ private static final int HOVER_TOOL_TIP_REVEAL_DURATION = 15;
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
@@ -90,35 +78,11 @@
R.dimen.taskbar_tooltip_horizontal_padding);
mHoverToolTipView.findViewById(R.id.text).setPadding(horizontalPadding, verticalPadding,
horizontalPadding, verticalPadding);
-
- AnimatorSet hoverCloseAnimator = new AnimatorSet();
- ObjectAnimator textCloseAnimator = ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 0);
- textCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0, 0.33f));
- ObjectAnimator alphaCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0);
- alphaCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.33f, 0.66f));
- ObjectAnimator scaleCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 0);
- scaleCloseAnimator.setInterpolator(Interpolators.STANDARD);
- hoverCloseAnimator.playTogether(
- textCloseAnimator,
- alphaCloseAnimator,
- scaleCloseAnimator);
- hoverCloseAnimator.setStartDelay(0);
- hoverCloseAnimator.setDuration(HOVER_TOOL_TIP_EXIT_DURATION);
- mHoverToolTipView.setCustomCloseAnimation(hoverCloseAnimator);
+ mHoverToolTipView.setAlpha(0);
AnimatorSet hoverOpenAnimator = new AnimatorSet();
- ObjectAnimator textOpenAnimator =
- ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 0, 255);
- textOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.15f, 0.75f));
- ObjectAnimator scaleOpenAnimator =
- ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 0f, 1f);
- scaleOpenAnimator.setInterpolator(Interpolators.EMPHASIZED);
ObjectAnimator alphaOpenAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0f, 1f);
- alphaOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0f, 0.33f));
- hoverOpenAnimator.playTogether(
- scaleOpenAnimator,
- textOpenAnimator,
- alphaOpenAnimator);
+ hoverOpenAnimator.play(alphaOpenAnimator);
hoverOpenAnimator.setDuration(HOVER_TOOL_TIP_REVEAL_DURATION);
mHoverToolTipView.setCustomOpenAnimation(hoverOpenAnimator);
@@ -131,28 +95,17 @@
@Override
public boolean onHover(View v, MotionEvent event) {
- boolean isAnyOtherFloatingViewOpen =
- AbstractFloatingView.hasOpenView(mActivity, TYPE_ALL_EXCEPT_ON_BOARD_POPUP);
- if (isAnyOtherFloatingViewOpen) {
- mHoverToolTipHandler.removeCallbacksAndMessages(null);
- }
+ boolean isFolderOpen = AbstractFloatingView.hasOpenView(mActivity, TYPE_FOLDER);
// If hover leaves a taskbar icon animate the tooltip closed.
if (event.getAction() == ACTION_HOVER_EXIT) {
- startHideHoverToolTip();
+ mHoverToolTipView.close(/* animate= */ false);
mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, false);
- return true;
- } else if (!isAnyOtherFloatingViewOpen && event.getAction() == ACTION_HOVER_ENTER) {
- // If hovering above a taskbar icon starts, animate the tooltip open. Do not
- // reveal if any floating views such as folders or edu pop-ups are open.
- startRevealHoverToolTip();
+ } else if (!isFolderOpen && event.getAction() == ACTION_HOVER_ENTER) {
+ // Do not reveal if any floating views such as folders or edu pop-ups are open.
+ revealHoverToolTip();
mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, true);
- return true;
}
- return false;
- }
-
- private void startRevealHoverToolTip() {
- mHoverToolTipHandler.post(mRevealHoverToolTipRunnable);
+ return true;
}
private void revealHoverToolTip() {
@@ -170,14 +123,4 @@
mHoverToolTipView.showAtLocation(mToolTipText, iconViewBounds.centerX(),
mTaskbarView.getTop(), /* shouldAutoClose= */ false);
}
-
- private void startHideHoverToolTip() {
- int accessibilityHideTimeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(
- mActivity, /* originalTimeout= */ 0, FLAG_CONTENT_TEXT);
- mHoverToolTipHandler.postDelayed(mHideHoverToolTipRunnable, accessibilityHideTimeout);
- }
-
- private void hideHoverToolTip() {
- mHoverToolTipView.close(/* animate = */ true);
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 2103ebb..9dee473 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -64,6 +64,10 @@
companion object {
private const val INDEX_LEFT = 0
private const val INDEX_RIGHT = 1
+
+ private fun Region.addBoundsToRegion(bounds: Rect?) {
+ bounds?.let { op(it, Region.Op.UNION) }
+ }
}
/** The bottom insets taskbar provides to the IME when IME is visible. */
@@ -128,46 +132,25 @@
}
}
+ val bubbleControllers = controllers.bubbleControllers.getOrNull()
val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
val bubblesTouchableHeight =
- if (controllers.bubbleControllers.isPresent) {
- controllers.bubbleControllers.get().bubbleStashController.touchableHeight
- } else {
- 0
- }
+ bubbleControllers?.bubbleStashController?.getTouchableHeight() ?: 0
+ // add bounds for task bar and bubble bar stash controllers
val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
-
- if (
- controllers.bubbleControllers.isPresent &&
- controllers.bubbleControllers.get().bubbleStashController.isBubblesShowingOnHome
- ) {
- val iconBounds =
- controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
- defaultTouchableRegion.set(
- iconBounds.left,
- iconBounds.top,
- iconBounds.right,
- iconBounds.bottom
- )
- } else {
- defaultTouchableRegion.set(
- 0,
- windowLayoutParams.height - touchableHeight,
- context.deviceProfile.widthPx,
- windowLayoutParams.height
- )
-
- // if there's an animating bubble add it to the touch region so that it's clickable
- val isAnimatingNewBubble =
- controllers.bubbleControllers
- .getOrNull()
- ?.bubbleBarViewController
- ?.isAnimatingNewBubble
- ?: false
- if (isAnimatingNewBubble) {
- val iconBounds =
- controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
- defaultTouchableRegion.op(iconBounds, Region.Op.UNION)
+ defaultTouchableRegion.set(
+ 0,
+ windowLayoutParams.height - touchableHeight,
+ context.deviceProfile.widthPx,
+ windowLayoutParams.height
+ )
+ if (bubbleControllers != null) {
+ val bubbleBarViewController = bubbleControllers.bubbleBarViewController
+ val isBubbleBarVisible = bubbleControllers.bubbleStashController.isBubbleBarVisible()
+ val isAnimatingNewBubble = bubbleBarViewController.isAnimatingNewBubble
+ // if bubble bar is visible or animating new bubble, add bar bounds to the touch region
+ if (isBubbleBarVisible || isAnimatingNewBubble) {
+ defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds)
}
}
@@ -358,13 +341,6 @@
*/
fun updateInsetsTouchability(insetsInfo: ViewTreeObserver.InternalInsetsInfo) {
insetsInfo.touchableRegion.setEmpty()
- // Always have nav buttons be touchable
- controllers.navbarButtonsViewController.addVisibleButtonsRegion(
- context.dragLayer,
- insetsInfo.touchableRegion
- )
- debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
-
val bubbleBarVisible =
controllers.bubbleControllers.isPresent &&
controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
@@ -426,7 +402,7 @@
// Include the bounds of the bubble bar in the touchable region if they exist.
if (bubbleBarBounds != null) {
- region.op(bubbleBarBounds, Region.Op.UNION)
+ region.addBoundsToRegion(bubbleBarBounds)
}
insetsInfo.touchableRegion.set(region)
debugTouchableRegion.lastSetTouchableReason = "Transient Taskbar is in Overview"
@@ -443,6 +419,12 @@
debugTouchableRegion.lastSetTouchableReason =
"Icons are not visible, but other components such as 3 buttons might be"
}
+ // Always have nav buttons be touchable
+ controllers.navbarButtonsViewController.addVisibleButtonsRegion(
+ context.dragLayer,
+ insetsInfo.touchableRegion
+ )
+ debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
context.excludeFromMagnificationRegion(insetsIsTouchableRegion)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 20ab32e..e6b3acd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -470,7 +470,8 @@
// We're changing state to home, should close open popups e.g. Taskbar AllApps
handleOpenFloatingViews = true;
}
- if (mLauncherState == LauncherState.OVERVIEW) {
+ if (mLauncherState == LauncherState.OVERVIEW
+ && !mControllers.taskbarActivityContext.isPhoneMode()) {
// Calling to update the insets in TaskbarInsetController#updateInsetsTouchability
mControllers.taskbarActivityContext.notifyUpdateLayoutParams();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index b697590..332eb95 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -53,6 +53,7 @@
import com.android.quickstep.util.LogUtils;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -69,6 +70,9 @@
private static final SystemShortcut.Factory<BaseTaskbarContext>
APP_INFO = SystemShortcut.AppInfo::new;
+ private static final SystemShortcut.Factory<BaseTaskbarContext>
+ BUBBLE = SystemShortcut.BubbleShortcut::new;
+
private final TaskbarActivityContext mContext;
private final PopupDataProvider mPopupDataProvider;
@@ -181,11 +185,17 @@
// Create a Stream of all applicable system shortcuts
private Stream<SystemShortcut.Factory> getSystemShortcuts() {
- // append split options to APP_INFO shortcut, the order here will reflect in the popup
- return Stream.concat(
- Stream.of(APP_INFO),
- mControllers.uiController.getSplitMenuOptions()
- );
+ // append split options to APP_INFO shortcut if not in Desktop Windowing mode, the order
+ // here will reflect in the popup
+ ArrayList<SystemShortcut.Factory> shortcuts = new ArrayList<>();
+ shortcuts.add(APP_INFO);
+ if (!mControllers.taskbarRecentAppsController.isInDesktopMode()) {
+ shortcuts.addAll(mControllers.uiController.getSplitMenuOptions().toList());
+ }
+ if (com.android.wm.shell.Flags.enableBubbleAnything()) {
+ shortcuts.add(BUBBLE);
+ }
+ return shortcuts.stream();
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 6b5e51f..737d031 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -27,7 +27,7 @@
import com.android.quickstep.RecentsModel
import com.android.quickstep.util.DesktopTask
import com.android.quickstep.util.GroupTask
-import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import java.io.PrintWriter
@@ -45,7 +45,8 @@
) : LoggableTaskbarController {
var canShowRunningApps =
- DesktopModeStatus.canEnterDesktopMode(context) && enableDesktopWindowingTaskbarRunningApps()
+ DesktopModeStatus.canEnterDesktopMode(context) &&
+ DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(context)
@VisibleForTesting
set(isEnabledFromTest) {
field = isEnabledFromTest
@@ -80,7 +81,7 @@
private val desktopVisibilityController: DesktopVisibilityController?
get() = desktopVisibilityControllerProvider()
- private val isInDesktopMode: Boolean
+ val isInDesktopMode: Boolean
get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
val runningTaskIds: Set<Int>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 5e7c7ce..4df0223 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -28,6 +28,7 @@
import android.view.animation.PathInterpolator;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -86,6 +87,10 @@
* Updates the scrim state based on the flags.
*/
public void updateStateForSysuiFlags(@SystemUiStateFlags long stateFlags, boolean skipAnim) {
+ if (mActivity.isPhoneMode()) {
+ // There is no scrim for the bar in the phone mode.
+ return;
+ }
if (isBubbleBarEnabled() && DisplayController.isTransientTaskbar(mActivity)) {
// These scrims aren't used if bubble bar & transient taskbar are active.
return;
@@ -97,10 +102,20 @@
private boolean shouldShowScrim() {
final boolean bubblesExpanded = (mSysUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
boolean isShadeVisible = (mSysUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
+ BubbleControllers bubbleControllers = mActivity.getBubbleControllers();
+ boolean isBubbleControllersPresented = bubbleControllers != null;
+ // when the taskbar is in persistent mode, we hide the task bar icons on bubble bar expand,
+ // which makes the taskbar invisible, so need to check if the bubble bar is not on home
+ // to show the scrim view
+ boolean showScrimForBubbles = bubblesExpanded
+ && !mTaskbarVisible
+ && isBubbleControllersPresented
+ && !DisplayController.isTransientTaskbar(mActivity)
+ && !bubbleControllers.bubbleStashController.isBubblesShowingOnHome();
return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible()
&& !isShadeVisible
&& !mControllers.taskbarStashController.isStashed()
- && mTaskbarVisible;
+ && (mTaskbarVisible || showScrimForBubbles);
}
private float getScrimAlpha() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 5d6fdc1..8a20131 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -96,7 +96,6 @@
public static final int FLAG_STASHED_SYSUI = 1 << 9; // app pinning,...
public static final int FLAG_STASHED_DEVICE_LOCKED = 1 << 10; // device is locked: keyguard, ...
public static final int FLAG_IN_OVERVIEW = 1 << 11; // launcher is in overview
- public static final int FLAG_IGNORE_IN_APP = 1 << 12; // used to sync with app launch animation
// If any of these flags are enabled, isInApp should return true.
private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
@@ -1022,6 +1021,10 @@
/** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
public void updateStateForSysuiFlags(long systemUiStateFlags, boolean skipAnim) {
+ if (mActivity.isPhoneMode()) {
+ return;
+ }
+
long animDuration = TASKBAR_STASH_DURATION;
long startDelay = 0;
@@ -1281,11 +1284,6 @@
*/
@Nullable
public Animator createSetStateAnimator(long flags, long duration) {
- // We do this when we want to synchronize the app launch and taskbar stash animations.
- if (hasAnyFlag(FLAG_IGNORE_IN_APP) && hasAnyFlag(flags, FLAG_IN_APP)) {
- flags = flags & ~FLAG_IN_APP;
- }
-
boolean isStashed = mStashCondition.test(flags);
if (DEBUG) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 144c0c2..5a5d6d0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -95,7 +95,8 @@
mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY);
mControllers.bubbleControllers.ifPresent(controllers -> {
controllers.bubbleBarViewController.setTranslationYForSwipe(transY);
- controllers.bubbleStashedHandleViewController.setTranslationYForSwipe(transY);
+ controllers.bubbleStashedHandleViewController.ifPresent(
+ controller -> controller.setTranslationYForSwipe(transY));
});
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index a2278ec..42bf8db 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -61,6 +61,8 @@
// Initialized in init.
protected TaskbarControllers mControllers;
+ protected boolean mSkipLauncherVisibilityChange;
+
@CallSuper
protected void init(TaskbarControllers taskbarControllers) {
mControllers = taskbarControllers;
@@ -174,11 +176,11 @@
|| mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
}
- /** Checks if the given {@link MotionEvent} is over the bubble bar stash handle. */
- public boolean isEventOverBubbleBarStashHandle(MotionEvent ev) {
+ /** Checks if the given {@link MotionEvent} is over the bubble bar views. */
+ public boolean isEventOverBubbleBarViews(MotionEvent ev) {
return mControllers.bubbleControllers.map(
bubbleControllers ->
- bubbleControllers.bubbleStashController.isEventOverStashHandle(ev))
+ bubbleControllers.bubbleStashController.isEventOverBubbleBarViews(ev))
.orElse(false);
}
@@ -418,4 +420,12 @@
public void setUserIsNotGoingHome(boolean isNotGoingHome) {
mControllers.taskbarStashController.setUserIsNotGoingHome(isNotGoingHome);
}
+
+ /**
+ * Sets whether to prevent taskbar from reacting to launcher visibility during the recents
+ * transition animation.
+ */
+ public void setSkipLauncherVisibilityChange(boolean skip) {
+ mSkipLauncherVisibilityChange = skip;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index e58069a..fc76972 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -669,8 +669,20 @@
return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates);
}
+ /**
+ * Gets visual bounds of the taskbar view. The visual bounds correspond to the taskbar touch
+ * area, rather than layout placement in the parent view.
+ */
+ public Rect getIconLayoutVisualBounds() {
+ return new Rect(mIconLayoutBounds);
+ }
+
+ /** Gets taskbar layout bounds in parent view. */
public Rect getIconLayoutBounds() {
- return mIconLayoutBounds;
+ Rect actualBounds = new Rect(mIconLayoutBounds);
+ actualBounds.top = getTop();
+ actualBounds.bottom = getBottom();
+ return actualBounds;
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index ffa4819..b8b85d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -96,7 +96,9 @@
public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5;
public static final int ALPHA_INDEX_SMALL_SCREEN = 6;
- private static final int NUM_ALPHA_CHANNELS = 7;
+
+ public static final int ALPHA_INDEX_BUBBLE_BAR = 7;
+ private static final int NUM_ALPHA_CHANNELS = 8;
private static boolean sEnableModelLoadingForTests = true;
@@ -272,6 +274,10 @@
OneShotPreDrawListener.add(mTaskbarView, listener);
}
+ public Rect getIconLayoutVisualBounds() {
+ return mTaskbarView.getIconLayoutVisualBounds();
+ }
+
public Rect getIconLayoutBounds() {
return mTaskbarView.getIconLayoutBounds();
}
@@ -462,14 +468,14 @@
if (mControllers.getSharedState().startTaskbarVariantIsTransient) {
float transY =
mTransientTaskbarDp.taskbarBottomMargin + (mTransientTaskbarDp.taskbarHeight
- - mTaskbarView.getIconLayoutBounds().bottom)
+ - mTaskbarView.getIconLayoutVisualBounds().bottom)
- (mPersistentTaskbarDp.taskbarHeight
- mTransientTaskbarDp.taskbarIconSize) / 2f;
taskbarIconTranslationYForPinningValue = mapRange(scale, 0f, transY);
} else {
float transY =
-mTransientTaskbarDp.taskbarBottomMargin + (mPersistentTaskbarDp.taskbarHeight
- - mTaskbarView.getIconLayoutBounds().bottom)
+ - mTaskbarView.getIconLayoutVisualBounds().bottom)
- (mTransientTaskbarDp.taskbarHeight
- mTransientTaskbarDp.taskbarIconSize) / 2f;
taskbarIconTranslationYForPinningValue = mapRange(scale, transY, 0f);
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index 619c9c4..c380c8d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -110,7 +110,7 @@
}
fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) {
- if (isVoiceInteractionWindowVisible == visible) {
+ if (isVoiceInteractionWindowVisible == visible || context.isPhoneMode) {
return
}
isVoiceInteractionWindowVisible = visible
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 5be0171..a36d5f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -15,13 +15,8 @@
*/
package com.android.launcher3.taskbar.bubbles;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_PERSONS_DATA;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-import static com.android.launcher3.icons.FastBitmapDrawable.WHITE_SCRIM_ALPHA;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
@@ -34,35 +29,13 @@
import android.annotation.BinderThread;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.content.pm.ShortcutInfo;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Path;
import android.graphics.Point;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.os.Bundle;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.PathParser;
-import android.view.LayoutInflater;
-import androidx.appcompat.content.res.AppCompatResources;
-
-import com.android.internal.graphics.ColorUtils;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.BubbleIconFactory;
-import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -76,6 +49,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -134,18 +108,16 @@
private static final Executor BUBBLE_STATE_EXECUTOR = Executors.newSingleThreadExecutor(
new SimpleThreadFactory("BubbleStateUpdates-", THREAD_PRIORITY_BACKGROUND));
- private final LauncherApps mLauncherApps;
- private final BubbleIconFactory mIconFactory;
private final SystemUiProxy mSystemUiProxy;
private BubbleBarItem mSelectedBubble;
- private BubbleBarOverflow mOverflowBubble;
private ImeVisibilityChecker mImeVisibilityChecker;
private BubbleBarViewController mBubbleBarViewController;
private BubbleStashController mBubbleStashController;
- private BubbleStashedHandleViewController mBubbleStashedHandleViewController;
+ private Optional<BubbleStashedHandleViewController> mBubbleStashedHandleViewController;
private BubblePinController mBubblePinController;
+ private BubbleCreator mBubbleCreator;
// Cache last sent top coordinate to avoid sending duplicate updates to shell
private int mLastSentBubbleBarTop;
@@ -166,6 +138,8 @@
List<RemovedBubble> removedBubbles;
List<String> bubbleKeysInOrder;
Point expandedViewDropTargetSize;
+ boolean showOverflow;
+ boolean showOverflowChanged;
// These need to be loaded in the background
BubbleBarBubble addedBubble;
@@ -184,6 +158,8 @@
removedBubbles = update.removedBubbles;
bubbleKeysInOrder = update.bubbleKeysInOrder;
expandedViewDropTargetSize = update.expandedViewDropTargetSize;
+ showOverflow = update.showOverflow;
+ showOverflowChanged = update.showOverflowChanged;
}
}
@@ -192,17 +168,6 @@
mBarView = bubbleView; // Need the view for inflating bubble views.
mSystemUiProxy = SystemUiProxy.INSTANCE.get(context);
-
- if (sBubbleBarEnabled) {
- mSystemUiProxy.setBubblesListener(this);
- }
- mLauncherApps = context.getSystemService(LauncherApps.class);
- mIconFactory = new BubbleIconFactory(context,
- context.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size),
- context.getResources().getDimensionPixelSize(R.dimen.bubblebar_badge_size),
- context.getResources().getColor(R.color.important_conversation),
- context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.importance_ring_stroke_width));
}
public void onDestroy() {
@@ -217,37 +182,22 @@
mBubbleStashController = bubbleControllers.bubbleStashController;
mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
mBubblePinController = bubbleControllers.bubblePinController;
+ mBubbleCreator = bubbleControllers.bubbleCreator;
bubbleControllers.runAfterInit(() -> {
mBubbleBarViewController.setHiddenForBubbles(
!sBubbleBarEnabled || mBubbles.isEmpty());
- mBubbleStashedHandleViewController.setHiddenForBubbles(
- !sBubbleBarEnabled || mBubbles.isEmpty());
+ mBubbleStashedHandleViewController.ifPresent(
+ controller -> controller.setHiddenForBubbles(
+ !sBubbleBarEnabled || mBubbles.isEmpty()));
mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse(
key -> setSelectedBubbleInternal(mBubbles.get(key)));
mBubbleBarViewController.setBoundsChangeListener(this::onBubbleBarBoundsChanged);
- });
- }
- /**
- * Creates and adds the overflow bubble to the bubble bar if it hasn't been created yet.
- *
- * <p>This should be called on the {@link #BUBBLE_STATE_EXECUTOR} executor to avoid inflating
- * the overflow multiple times.
- */
- private void createAndAddOverflowIfNeeded() {
- if (mOverflowBubble == null) {
- BubbleBarOverflow overflow = createOverflow(mContext);
- MAIN_EXECUTOR.execute(() -> {
- // we're on the main executor now, so check that the overflow hasn't been created
- // again to avoid races.
- if (mOverflowBubble == null) {
- mBubbleBarViewController.addBubble(
- overflow, /* isExpanding= */ false, /* suppressAnimation= */ true);
- mOverflowBubble = overflow;
- }
- });
- }
+ if (sBubbleBarEnabled) {
+ mSystemUiProxy.setBubblesListener(this);
+ }
+ });
}
/**
@@ -258,10 +208,11 @@
mBubbleBarViewController.setHiddenForSysui(hideBubbleBar);
boolean hideHandleView = (flags & MASK_HIDE_HANDLE_VIEW) != 0;
- mBubbleStashedHandleViewController.setHiddenForSysui(hideHandleView);
+ mBubbleStashedHandleViewController.ifPresent(
+ controller -> controller.setHiddenForSysui(hideHandleView));
boolean sysuiLocked = (flags & MASK_SYSUI_LOCKED) != 0;
- mBubbleStashController.onSysuiLockedStateChange(sysuiLocked);
+ mBubbleStashController.setSysuiLocked(sysuiLocked);
}
//
@@ -279,23 +230,25 @@
|| !update.currentBubbleList.isEmpty()) {
// We have bubbles to load
BUBBLE_STATE_EXECUTOR.execute(() -> {
- createAndAddOverflowIfNeeded();
if (update.addedBubble != null) {
- viewUpdate.addedBubble = populateBubble(mContext, update.addedBubble, mBarView,
+ viewUpdate.addedBubble = mBubbleCreator.populateBubble(mContext,
+ update.addedBubble,
+ mBarView,
null /* existingBubble */);
}
if (update.updatedBubble != null) {
BubbleBarBubble existingBubble = mBubbles.get(update.updatedBubble.getKey());
viewUpdate.updatedBubble =
- populateBubble(mContext, update.updatedBubble, mBarView,
+ mBubbleCreator.populateBubble(mContext, update.updatedBubble,
+ mBarView,
existingBubble);
}
if (update.currentBubbleList != null && !update.currentBubbleList.isEmpty()) {
List<BubbleBarBubble> currentBubbles = new ArrayList<>();
for (int i = 0; i < update.currentBubbleList.size(); i++) {
- BubbleBarBubble b =
- populateBubble(mContext, update.currentBubbleList.get(i), mBarView,
- null /* existingBubble */);
+ BubbleBarBubble b = mBubbleCreator.populateBubble(mContext,
+ update.currentBubbleList.get(i), mBarView,
+ null /* existingBubble */);
currentBubbles.add(b);
}
viewUpdate.currentBubbles = currentBubbles;
@@ -322,25 +275,38 @@
BubbleBarBubble bubbleToSelect = null;
- if (update.addedBubble != null && update.removedBubbles.size() == 1) {
+ if (Flags.enableOptionalBubbleOverflow()
+ && update.showOverflowChanged && !update.showOverflow && update.addedBubble != null
+ && update.removedBubbles.isEmpty()) {
+ // A bubble was added from the overflow (& now it's empty / not showing)
+ mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
+ mBubbleBarViewController.removeOverflowAndAddBubble(update.addedBubble);
+ } else if (update.addedBubble != null && update.removedBubbles.size() == 1) {
// we're adding and removing a bubble at the same time. handle this as a single update.
RemovedBubble removedBubble = update.removedBubbles.get(0);
BubbleBarBubble bubbleToRemove = mBubbles.remove(removedBubble.getKey());
mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
+ boolean showOverflow = update.showOverflowChanged && update.showOverflow;
if (bubbleToRemove != null) {
mBubbleBarViewController.addBubbleAndRemoveBubble(update.addedBubble,
- bubbleToRemove, isExpanding, suppressAnimation);
+ bubbleToRemove, isExpanding, suppressAnimation, showOverflow);
} else {
mBubbleBarViewController.addBubble(update.addedBubble, isExpanding,
suppressAnimation);
Log.w(TAG, "trying to remove bubble that doesn't exist: " + removedBubble.getKey());
}
} else {
+ boolean overflowNeedsToBeAdded = Flags.enableOptionalBubbleOverflow()
+ && update.showOverflowChanged && update.showOverflow;
if (!update.removedBubbles.isEmpty()) {
for (int i = 0; i < update.removedBubbles.size(); i++) {
RemovedBubble removedBubble = update.removedBubbles.get(i);
BubbleBarBubble bubble = mBubbles.remove(removedBubble.getKey());
- if (bubble != null) {
+ if (bubble != null && overflowNeedsToBeAdded) {
+ // First removal, show the overflow
+ overflowNeedsToBeAdded = false;
+ mBubbleBarViewController.addOverflowAndRemoveBubble(bubble);
+ } else if (bubble != null) {
mBubbleBarViewController.removeBubble(bubble);
} else {
Log.w(TAG, "trying to remove bubble that doesn't exist: "
@@ -353,6 +319,11 @@
mBubbleBarViewController.addBubble(update.addedBubble, isExpanding,
suppressAnimation);
}
+ if (Flags.enableOptionalBubbleOverflow()
+ && update.showOverflowChanged
+ && update.showOverflow != mBubbleBarViewController.isOverflowAdded()) {
+ mBubbleBarViewController.showOverflow(update.showOverflow);
+ }
}
// if a bubble was updated upstream, but removed before the update was received, add it back
@@ -384,10 +355,14 @@
}
}
}
+ if (Flags.enableOptionalBubbleOverflow() && update.initialState && update.showOverflow) {
+ mBubbleBarViewController.showOverflow(true);
+ }
// Adds and removals have happened, update visibility before any other visual changes.
mBubbleBarViewController.setHiddenForBubbles(mBubbles.isEmpty());
- mBubbleStashedHandleViewController.setHiddenForBubbles(mBubbles.isEmpty());
+ mBubbleStashedHandleViewController.ifPresent(
+ controller -> controller.setHiddenForBubbles(mBubbles.isEmpty()));
if (mBubbles.isEmpty()) {
// all bubbles were removed. clear the selected bubble
@@ -525,133 +500,6 @@
// Loading data for the bubbles
//
- @Nullable
- private BubbleBarBubble populateBubble(Context context, BubbleInfo b, BubbleBarView bbv,
- @Nullable BubbleBarBubble existingBubble) {
- String appName;
- Bitmap badgeBitmap;
- Bitmap bubbleBitmap;
- Path dotPath;
- int dotColor;
-
- boolean isImportantConvo = b.isImportantConversation();
-
- ShortcutRequest.QueryResult result = new ShortcutRequest(context,
- new UserHandle(b.getUserId()))
- .forPackage(b.getPackageName(), b.getShortcutId())
- .query(FLAG_MATCH_DYNAMIC
- | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
- | FLAG_MATCH_CACHED
- | FLAG_GET_PERSONS_DATA);
-
- ShortcutInfo shortcutInfo = result.size() > 0 ? result.get(0) : null;
- if (shortcutInfo == null) {
- Log.w(TAG, "No shortcutInfo found for bubble: " + b.getKey()
- + " with shortcutId: " + b.getShortcutId());
- }
-
- ApplicationInfo appInfo;
- try {
- appInfo = mLauncherApps.getApplicationInfo(
- b.getPackageName(),
- 0,
- new UserHandle(b.getUserId()));
- } catch (PackageManager.NameNotFoundException e) {
- // If we can't find package... don't think we should show the bubble.
- Log.w(TAG, "Unable to find packageName: " + b.getPackageName());
- return null;
- }
- if (appInfo == null) {
- Log.w(TAG, "Unable to find appInfo: " + b.getPackageName());
- return null;
- }
- PackageManager pm = context.getPackageManager();
- appName = String.valueOf(appInfo.loadLabel(pm));
- Drawable appIcon = appInfo.loadUnbadgedIcon(pm);
- Drawable badgedIcon = pm.getUserBadgedIcon(appIcon, new UserHandle(b.getUserId()));
-
- // Badged bubble image
- Drawable bubbleDrawable = mIconFactory.getBubbleDrawable(context, shortcutInfo,
- b.getIcon());
- if (bubbleDrawable == null) {
- // Default to app icon
- bubbleDrawable = appIcon;
- }
-
- BitmapInfo badgeBitmapInfo = mIconFactory.getBadgeBitmap(badgedIcon, isImportantConvo);
- badgeBitmap = badgeBitmapInfo.icon;
-
- float[] bubbleBitmapScale = new float[1];
- bubbleBitmap = mIconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
-
- // Dot color & placement
- Path iconPath = PathParser.createPathFromPathData(
- context.getResources().getString(
- com.android.internal.R.string.config_icon_mask));
- Matrix matrix = new Matrix();
- float scale = bubbleBitmapScale[0];
- float radius = BubbleView.DEFAULT_PATH_SIZE / 2f;
- matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
- radius /* pivot y */);
- iconPath.transform(matrix);
- dotPath = iconPath;
- dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
- Color.WHITE, WHITE_SCRIM_ALPHA / 255f);
-
- if (existingBubble == null) {
- LayoutInflater inflater = LayoutInflater.from(context);
- BubbleView bubbleView = (BubbleView) inflater.inflate(
- R.layout.bubblebar_item_view, bbv, false /* attachToRoot */);
-
- BubbleBarBubble bubble = new BubbleBarBubble(b, bubbleView,
- badgeBitmap, bubbleBitmap, dotColor, dotPath, appName);
- bubbleView.setBubble(bubble);
- return bubble;
- } else {
- // If we already have a bubble (so it already has an inflated view), update it.
- existingBubble.setInfo(b);
- existingBubble.setBadge(badgeBitmap);
- existingBubble.setIcon(bubbleBitmap);
- existingBubble.setDotColor(dotColor);
- existingBubble.setDotPath(dotPath);
- existingBubble.setAppName(appName);
- return existingBubble;
- }
- }
-
- private BubbleBarOverflow createOverflow(Context context) {
- Bitmap bitmap = createOverflowBitmap(context);
- LayoutInflater inflater = LayoutInflater.from(context);
- BubbleView bubbleView = (BubbleView) inflater.inflate(
- R.layout.bubble_bar_overflow_button, mBarView, false /* attachToRoot */);
- BubbleBarOverflow overflow = new BubbleBarOverflow(bubbleView);
- bubbleView.setOverflow(overflow, bitmap);
- return overflow;
- }
-
- private Bitmap createOverflowBitmap(Context context) {
- Drawable iconDrawable = AppCompatResources.getDrawable(mContext,
- R.drawable.bubble_ic_overflow_button);
-
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[]{
- R.attr.materialColorOnPrimaryFixed,
- R.attr.materialColorPrimaryFixed
- });
- int overflowIconColor = ta.getColor(0, Color.WHITE);
- int overflowBackgroundColor = ta.getColor(1, Color.BLACK);
- ta.recycle();
-
- iconDrawable.setTint(overflowIconColor);
-
- int inset = context.getResources().getDimensionPixelSize(R.dimen.bubblebar_overflow_inset);
- Drawable foreground = new InsetDrawable(iconDrawable, inset);
- Drawable drawable = new AdaptiveIconDrawable(new ColorDrawable(overflowBackgroundColor),
- foreground);
-
- return mIconFactory.createBadgedIconBitmap(drawable).icon;
- }
-
private void onBubbleBarBoundsChanged() {
int newTop = mBarView.getRestingTopPositionOnScreen();
if (newTop != mLastSentBubbleBarTop) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index 9e5ffc9..a6b0860 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -27,6 +27,7 @@
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.common.bubbles.BaseBubblePinController
import com.android.wm.shell.common.bubbles.BubbleBarLocation
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 7d27a90..ffab936 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -124,8 +124,6 @@
private final BubbleBarBackground mBubbleBarBackground;
- private boolean mIsAnimatingNewBubble = false;
-
/**
* The current bounds of all the bubble bar. Note that these bounds may not account for
* translation. The bounds should be retrieved using {@link #getBubbleBarBounds()} which
@@ -418,6 +416,7 @@
LayoutParams lp = (LayoutParams) getLayoutParams();
lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
setLayoutParams(lp); // triggers a relayout
+ updateBubbleAccessibilityStates();
}
/**
@@ -648,7 +647,9 @@
}
setAlphaDuringBubbleDrag(1f);
setTranslationX(0f);
- setAlpha(1f);
+ if (getBubbleChildCount() > 0) {
+ setAlpha(1f);
+ }
}
/**
@@ -660,13 +661,25 @@
return displayHeight - bubbleBarHeight + (int) mController.getBubbleBarTranslationY();
}
- /**
- * Updates the bounds with translation that may have been applied and returns the result.
- */
+ /** Returns the bounds with translation that may have been applied. */
public Rect getBubbleBarBounds() {
- mBubbleBarBounds.top = getTop() + (int) getTranslationY() + mPointerSize;
- mBubbleBarBounds.bottom = getBottom() + (int) getTranslationY();
- return mBubbleBarBounds;
+ Rect bounds = new Rect(mBubbleBarBounds);
+ bounds.top = getTop() + (int) getTranslationY() + mPointerSize;
+ bounds.bottom = getBottom() + (int) getTranslationY();
+ return bounds;
+ }
+
+ /** Returns the expanded bounds with translation that may have been applied. */
+ public Rect getBubbleBarExpandedBounds() {
+ Rect expandedBounds = getBubbleBarBounds();
+ if (!isExpanded() || isExpanding()) {
+ if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+ expandedBounds.right = expandedBounds.left + (int) expandedWidth();
+ } else {
+ expandedBounds.left = expandedBounds.right - (int) expandedWidth();
+ }
+ }
+ return expandedBounds;
}
/**
@@ -701,25 +714,17 @@
return mRelativePivotY;
}
- /** Notifies the bubble bar that a new bubble animation is starting. */
- public void onAnimatingBubbleStarted() {
- mIsAnimatingNewBubble = true;
- }
-
- /** Notifies the bubble bar that a new bubble animation is complete. */
- public void onAnimatingBubbleCompleted() {
- mIsAnimatingNewBubble = false;
- }
-
/** Add a new bubble to the bubble bar. */
public void addBubble(BubbleView bubble) {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) mIconSize, (int) mIconSize,
Gravity.LEFT);
+ final int index = bubble.isOverflow() ? getChildCount() : 0;
+
if (isExpanded()) {
// if we're expanded scale the new bubble in
bubble.setScaleX(0f);
bubble.setScaleY(0f);
- addView(bubble, 0, lp);
+ addView(bubble, index, lp);
bubble.showDotIfNeeded(/* animate= */ false);
mBubbleAnimator = new BubbleAnimator(mIconSize, mExpandedBarIconsSpacing,
@@ -748,23 +753,34 @@
};
mBubbleAnimator.animateNewBubble(indexOfChild(mSelectedBubbleView), listener);
} else {
- addView(bubble, 0, lp);
+ addView(bubble, index, lp);
}
}
/** Add a new bubble and remove an old bubble from the bubble bar. */
- public void addBubbleAndRemoveBubble(View addedBubble, View removedBubble) {
+ public void addBubbleAndRemoveBubble(BubbleView addedBubble, BubbleView removedBubble,
+ Runnable onEndRunnable) {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) mIconSize, (int) mIconSize,
Gravity.LEFT);
+ boolean isOverflowSelected = mSelectedBubbleView.isOverflow();
+ boolean removingOverflow = removedBubble.isOverflow();
+ boolean addingOverflow = addedBubble.isOverflow();
+
if (!isExpanded()) {
removeView(removedBubble);
- addView(addedBubble, 0, lp);
+ int index = addingOverflow ? getChildCount() : 0;
+ addView(addedBubble, index, lp);
return;
}
+ int index = addingOverflow ? getChildCount() : 0;
addedBubble.setScaleX(0f);
addedBubble.setScaleY(0f);
- addView(addedBubble, 0, lp);
+ addView(addedBubble, index, lp);
+ if (isOverflowSelected && removingOverflow) {
+ // The added bubble will be selected
+ mSelectedBubbleView = addedBubble;
+ }
int indexOfSelectedBubble = indexOfChild(mSelectedBubbleView);
int indexOfBubbleToRemove = indexOfChild(removedBubble);
@@ -777,6 +793,9 @@
removeView(removedBubble);
updateWidth();
mBubbleAnimator = null;
+ if (onEndRunnable != null) {
+ onEndRunnable.run();
+ }
}
@Override
@@ -875,6 +894,33 @@
updateNotificationDotsIfCollapsed();
}
+ /**
+ * Return child views in the order which they are shown on the screen.
+ * <p>
+ * Child views (bubbles) are always ordered based on recency. The most recent bubble is at index
+ * 0.
+ * For example if the child views are (1)(2)(3) then (1) is the most recent bubble and at index
+ * 0.<br>
+ *
+ * How bubbles show up on the screen depends on the bubble bar location. If the bar is on the
+ * left, the most recent bubble is shown on the right. The bubbles from the example above would
+ * be shown as: (3)(2)(1).<br>
+ *
+ * If bubble bar is on the right, then the most recent bubble is on the left. Bubbles from the
+ * example above would be shown as: (1)(2)(3).
+ */
+ private List<View> getChildViewsInOnScreenOrder() {
+ List<View> childViews = new ArrayList<>(getChildCount());
+ for (int i = 0; i < getChildCount(); i++) {
+ childViews.add(getChildAt(i));
+ }
+ if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+ // Visually child views are shown in reverse order when bar is on the left
+ return childViews.reversed();
+ }
+ return childViews;
+ }
+
private void updateNotificationDotsIfCollapsed() {
if (isExpanded()) {
return;
@@ -924,7 +970,7 @@
final float currentWidth = getWidth();
final float expandedWidth = expandedWidth();
final float collapsedWidth = collapsedWidth();
- int bubbleCount = getChildCount();
+ int childCount = getChildCount();
float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0);
float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight();
// When translating X & Y the scale is ignored, so need to deduct it from the translations
@@ -932,7 +978,7 @@
final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl());
// elevation state is opposite to widthState - when expanded all icons are flat
float elevationState = (1 - widthState);
- for (int i = 0; i < bubbleCount; i++) {
+ for (int i = 0; i < childCount; i++) {
BubbleView bv = (BubbleView) getChildAt(i);
if (bv == mDraggedBubbleView || bv == mDismissedByDragBubbleView) {
// Skip the dragged bubble. Its translation is managed by the drag controller.
@@ -951,9 +997,9 @@
bv.setTranslationY(ty);
// the position of the bubble when the bar is fully expanded
- final float expandedX = getExpandedBubbleTranslationX(i, bubbleCount, onLeft);
+ final float expandedX = getExpandedBubbleTranslationX(i, childCount, onLeft);
// the position of the bubble when the bar is fully collapsed
- final float collapsedX = getCollapsedBubbleTranslationX(i, bubbleCount, onLeft);
+ final float collapsedX = getCollapsedBubbleTranslationX(i, childCount, onLeft);
// slowly animate elevation while keeping correct Z ordering
float fullElevationForChild = (MAX_BUBBLES * mBubbleElevation) - i;
@@ -981,13 +1027,10 @@
final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
final float targetX = collapsedX + collapsedBarShift;
bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
- // If we're fully collapsed, hide all bubbles except for the first 2. If there are
- // only 2 bubbles, hide the second bubble as well because it's the overflow.
+ // If we're fully collapsed, hide all bubbles except for the first 2, excluding
+ // the overflow.
if (widthState == 0) {
- if (i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
- bv.setAlpha(0);
- } else if (i == MAX_VISIBLE_BUBBLES_COLLAPSED - 1
- && bubbleCount == MAX_VISIBLE_BUBBLES_COLLAPSED) {
+ if (bv.isOverflow() || i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
bv.setAlpha(0);
} else {
bv.setAlpha(1);
@@ -1043,22 +1086,26 @@
return translationX - getScaleIconShift();
}
- private float getCollapsedBubbleTranslationX(int bubbleIndex, int bubbleCount, boolean onLeft) {
- if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
+ private float getCollapsedBubbleTranslationX(int bubbleIndex, int childCount, boolean onLeft) {
+ if (bubbleIndex < 0 || bubbleIndex >= childCount) {
return 0;
}
float translationX;
if (onLeft) {
- // Shift the first bubble only if there are more bubbles in addition to overflow
- translationX = mBubbleBarPadding + (
- bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
- ? mIconOverlapAmount : 0);
+ // Shift the first bubble only if there are more bubbles
+ if (bubbleIndex == 0 && getBubbleChildCount() >= MAX_VISIBLE_BUBBLES_COLLAPSED) {
+ translationX = mIconOverlapAmount;
+ } else {
+ translationX = 0f;
+ }
} else {
- translationX = mBubbleBarPadding + (
- bubbleIndex == 0 || bubbleCount <= MAX_VISIBLE_BUBBLES_COLLAPSED
- ? 0 : mIconOverlapAmount);
+ if (bubbleIndex == 1 && getBubbleChildCount() >= MAX_VISIBLE_BUBBLES_COLLAPSED) {
+ translationX = mIconOverlapAmount;
+ } else {
+ translationX = 0f;
+ }
}
- return translationX - getScaleIconShift();
+ return mBubbleBarPadding + translationX - getScaleIconShift();
}
/**
@@ -1239,6 +1286,13 @@
}
/**
+ * Returns whether the bubble bar is expanding.
+ */
+ public boolean isExpanding() {
+ return mWidthAnimator.isRunning() && mIsBarExpanded;
+ }
+
+ /**
* Get width of the bubble bar as if it would be expanded.
*
* @return width of the bubble bar in its expanded state, regardless of current width
@@ -1256,15 +1310,20 @@
}
private float collapsedWidth() {
- final int childCount = getChildCount();
+ final int bubbleChildCount = getBubbleChildCount();
final float horizontalPadding = 2 * mBubbleBarPadding;
- // If there are more than 2 bubbles, the first 2 should be visible when collapsed.
- // Otherwise just the first bubble should be visible because we don't show the overflow.
- return childCount > MAX_VISIBLE_BUBBLES_COLLAPSED
+ // If there are more than 2 bubbles, the first 2 should be visible when collapsed,
+ // excluding the overflow.
+ return bubbleChildCount >= MAX_VISIBLE_BUBBLES_COLLAPSED
? getScaledIconSize() + mIconOverlapAmount + horizontalPadding
: getScaledIconSize() + horizontalPadding;
}
+ /** Returns the child count excluding the overflow if it's present. */
+ private int getBubbleChildCount() {
+ return hasOverflow() ? getChildCount() - 1 : getChildCount();
+ }
+
private float getBubbleBarExpandedHeight() {
return getBubbleBarCollapsedHeight() + mPointerSize;
}
@@ -1288,9 +1347,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mIsAnimatingNewBubble) {
- mController.onBubbleBarTouchedWhileAnimating();
- }
+ mController.onBubbleBarTouched();
if (!mIsBarExpanded) {
// When the bar is collapsed, all taps on it should expand it.
return true;
@@ -1298,13 +1355,8 @@
return super.onInterceptTouchEvent(ev);
}
- /** Whether a new bubble is currently animating. */
- public boolean isAnimatingNewBubble() {
- return mIsAnimatingNewBubble;
- }
-
- private boolean hasOverview() {
- // Overview is always the last bubble
+ private boolean hasOverflow() {
+ // Overflow is always the last bubble
View lastChild = getChildAt(getChildCount() - 1);
if (lastChild instanceof BubbleView bubbleView) {
return bubbleView.getBubble() instanceof BubbleBarOverflow;
@@ -1313,21 +1365,39 @@
}
private void updateBubbleAccessibilityStates() {
- final int childA11y;
if (mIsBarExpanded) {
// Bar is expanded, focus on the bubbles
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
- childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+
+ // Set up a11y navigation order. Get list of child views in the order they are shown
+ // on screen. And use that to set up navigation so that swiping left focuses the view
+ // on the left and swiping right focuses view on the right.
+ View prevChild = null;
+ for (View childView : getChildViewsInOnScreenOrder()) {
+ childView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ childView.setFocusable(true);
+ final View finalPrevChild = prevChild;
+ // Always need to set a new delegate to clear out any previous.
+ childView.setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ if (finalPrevChild != null) {
+ info.setTraversalAfter(finalPrevChild);
+ }
+ }
+ });
+ prevChild = childView;
+ }
} else {
// Bar is collapsed, only focus on the bar
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_NO;
- }
- for (int i = 0; i < getChildCount(); i++) {
- getChildAt(i).setImportantForAccessibility(childA11y);
- // Only allowing focusing on bubbles when bar is expanded. Otherwise, in talkback mode,
- // bubbles can be navigates to in collapsed mode.
- getChildAt(i).setFocusable(mIsBarExpanded);
+ for (int i = 0; i < getChildCount(); i++) {
+ View childView = getChildAt(i);
+ childView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ childView.setFocusable(false);
+ }
}
}
@@ -1336,7 +1406,7 @@
CharSequence contentDesc = firstChild != null ? firstChild.getContentDescription() : "";
// Don't count overflow if it exists
- int bubbleCount = getChildCount() - (hasOverview() ? 1 : 0);
+ int bubbleCount = getChildCount() - (hasOverflow() ? 1 : 0);
if (bubbleCount > 1) {
contentDesc = getResources().getString(R.string.bubble_bar_description_multiple_bubbles,
contentDesc, bubbleCount - 1);
@@ -1417,7 +1487,6 @@
pw.println(" bubble key: " + key);
}
pw.println(" isExpanded: " + isExpanded());
- pw.println(" mIsAnimatingNewBubble: " + mIsAnimatingNewBubble);
if (mBubbleAnimator != null) {
pw.println(" mBubbleAnimator.isRunning(): " + mBubbleAnimator.isRunning());
pw.println(" mBubbleAnimator is null");
@@ -1442,8 +1511,8 @@
/** Returns the translation Y that the bubble bar should have. */
float getBubbleBarTranslationY();
- /** Notifies the controller that the bubble bar was touched while it was animating. */
- void onBubbleBarTouchedWhileAnimating();
+ /** Notifies the controller that the bubble bar was touched. */
+ void onBubbleBarTouched();
/** Requests the controller to expand bubble bar */
void expandBubbleBar();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 9270f68..4fe4ace 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -39,6 +39,7 @@
import com.android.launcher3.taskbar.TaskbarInsetsController;
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.taskbar.bubbles.animation.BubbleBarViewAnimator;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.SystemUiProxy;
@@ -71,9 +72,11 @@
private BubbleDragController mBubbleDragController;
private TaskbarStashController mTaskbarStashController;
private TaskbarInsetsController mTaskbarInsetsController;
+ private TaskbarViewPropertiesProvider mTaskbarViewPropertiesProvider;
private View.OnClickListener mBubbleClickListener;
private View.OnClickListener mBubbleBarClickListener;
private BubbleView.Controller mBubbleViewController;
+ private BubbleBarOverflow mOverflowBubble;
// These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
private final MultiValueAlpha mBubbleBarAlpha;
@@ -90,9 +93,11 @@
private boolean mHiddenForNoBubbles = true;
private boolean mShouldShowEducation;
+ public boolean mOverflowAdded;
+
private BubbleBarViewAnimator mBubbleBarViewAnimator;
- private TimeSource mTimeSource = System::currentTimeMillis;
+ private final TimeSource mTimeSource = System::currentTimeMillis;
@Nullable
private BubbleBarBoundsChangeListener mBoundsChangeListener;
@@ -106,13 +111,16 @@
R.dimen.bubblebar_icon_size);
}
- public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
+ /** Initializes controller. */
+ public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers,
+ TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) {
mBubbleStashController = bubbleControllers.bubbleStashController;
mBubbleBarController = bubbleControllers.bubbleBarController;
mBubbleDragController = bubbleControllers.bubbleDragController;
mTaskbarStashController = controllers.taskbarStashController;
mTaskbarInsetsController = controllers.taskbarInsetsController;
mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
+ mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
onBubbleBarConfigurationChanged(/* animate= */ false);
mActivity.addOnDeviceProfileChangeListener(
dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
@@ -120,6 +128,7 @@
mBubbleClickListener = v -> onBubbleClicked((BubbleView) v);
mBubbleBarClickListener = v -> expandBubbleBar();
mBubbleDragController.setupBubbleBarView(mBarView);
+ mOverflowBubble = bubbleControllers.bubbleCreator.createOverflow(mBarView);
mBarView.setOnClickListener(mBubbleBarClickListener);
mBarView.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
@@ -135,8 +144,8 @@
}
@Override
- public void onBubbleBarTouchedWhileAnimating() {
- BubbleBarViewController.this.onBubbleBarTouchedWhileAnimating();
+ public void onBubbleBarTouched() {
+ BubbleBarViewController.this.onBubbleBarTouched();
}
@Override
@@ -197,9 +206,12 @@
}
}
- private void onBubbleBarTouchedWhileAnimating() {
- mBubbleBarViewAnimator.onBubbleBarTouchedWhileAnimating();
- mBubbleStashController.onNewBubbleAnimationInterrupted(false, mBarView.getTranslationY());
+ private void onBubbleBarTouched() {
+ if (isAnimatingNewBubble()) {
+ mBubbleBarViewAnimator.onBubbleBarTouchedWhileAnimating();
+ mBubbleStashController.onNewBubbleAnimationInterrupted(false,
+ mBarView.getTranslationY());
+ }
}
private void expandBubbleBar() {
@@ -298,7 +310,11 @@
/** Whether a new bubble is animating. */
public boolean isAnimatingNewBubble() {
- return mBarView.isAnimatingNewBubble();
+ return mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.isAnimating();
+ }
+
+ public boolean isNewBubbleAnimationRunningOrPending() {
+ return mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.hasAnimation();
}
/** The horizontal margin of the bubble bar from the edge of the screen. */
@@ -342,6 +358,7 @@
if (hidden) {
mBarView.setAlpha(0);
mBarView.setExpanded(false);
+ updatePersistentTaskbar(/* isBubbleBarExpanded = */ false);
}
mActivity.bubbleBarVisibilityChanged(!hidden);
}
@@ -386,7 +403,8 @@
int newIconSize;
int newPadding;
Resources res = mActivity.getResources();
- if (mBubbleStashController.isBubblesShowingOnHome()) {
+ if (mBubbleStashController.isBubblesShowingOnHome()
+ || mBubbleStashController.isTransientTaskBar()) {
newIconSize = getBubbleBarIconSizeFromDeviceProfile(res);
newPadding = getBubbleBarPaddingFromDeviceProfile(res);
} else {
@@ -478,8 +496,10 @@
/** Adds a new bubble and removes an old bubble at the same time. */
public void addBubbleAndRemoveBubble(BubbleBarBubble addedBubble,
- BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation) {
- mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView());
+ BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation,
+ boolean addOverflowToo) {
+ mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView(),
+ addOverflowToo ? () -> showOverflow(true) : null);
addedBubble.getView().setOnClickListener(mBubbleClickListener);
addedBubble.getView().setController(mBubbleViewController);
removedBubble.getView().setController(null);
@@ -489,6 +509,48 @@
}
}
+ /** Whether the overflow view is added to the bubble bar. */
+ public boolean isOverflowAdded() {
+ return mOverflowAdded;
+ }
+
+ /** Shows or hides the overflow view. */
+ public void showOverflow(boolean showOverflow) {
+ if (mOverflowAdded == showOverflow) return;
+ mOverflowAdded = showOverflow;
+ if (mOverflowAdded) {
+ mBarView.addBubble(mOverflowBubble.getView());
+ mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
+ mOverflowBubble.getView().setController(mBubbleViewController);
+ } else {
+ mBarView.removeBubble(mOverflowBubble.getView());
+ mOverflowBubble.getView().setOnClickListener(null);
+ mOverflowBubble.getView().setController(null);
+ }
+ }
+
+ /** Adds the overflow view to the bubble bar while animating a view away. */
+ public void addOverflowAndRemoveBubble(BubbleBarBubble removedBubble) {
+ if (mOverflowAdded) return;
+ mOverflowAdded = true;
+ mBarView.addBubbleAndRemoveBubble(mOverflowBubble.getView(), removedBubble.getView(),
+ null /* onEndRunnable */);
+ mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
+ mOverflowBubble.getView().setController(mBubbleViewController);
+ removedBubble.getView().setController(null);
+ }
+
+ /** Removes the overflow view to the bubble bar while animating a view in. */
+ public void removeOverflowAndAddBubble(BubbleBarBubble addedBubble) {
+ if (!mOverflowAdded) return;
+ mOverflowAdded = false;
+ mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), mOverflowBubble.getView(),
+ null /* onEndRunnable */);
+ addedBubble.getView().setOnClickListener(mBubbleClickListener);
+ addedBubble.getView().setController(mBubbleViewController);
+ mOverflowBubble.getView().setController(null);
+ }
+
/**
* Adds the provided bubble to the bubble bar.
*/
@@ -499,15 +561,12 @@
mBubbleDragController.setupBubbleView(b.getView());
b.getView().setController(mBubbleViewController);
- if (b instanceof BubbleBarOverflow) {
- return;
- }
-
if (suppressAnimation || !(b instanceof BubbleBarBubble bubble)) {
// the bubble bar and handle are initialized as part of the first bubble animation.
// if the animation is suppressed, immediately stash or show the bubble bar to
// ensure they've been initialized.
- if (mTaskbarStashController.isInApp()) {
+ if (mTaskbarStashController.isInApp()
+ && mBubbleStashController.isTransientTaskBar()) {
mBubbleStashController.stashBubbleBarImmediate();
} else {
mBubbleStashController.showBubbleBarImmediate();
@@ -530,15 +589,16 @@
mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
return;
}
-
- if (mBubbleStashController.isBubblesShowingOnHome() && !isExpanding && !isExpanded()) {
- mBubbleBarViewAnimator.animateBubbleBarForCollapsed(bubble);
+ boolean persistentTaskbarOrOnHome = mBubbleStashController.isBubblesShowingOnHome()
+ || !mBubbleStashController.isTransientTaskBar();
+ if (persistentTaskbarOrOnHome && !isExpanded()) {
+ mBubbleBarViewAnimator.animateBubbleBarForCollapsed(bubble, isExpanding);
return;
}
- // only animate the new bubble if we're in an app and not auto expanding
- if (isInApp && !isExpanding && !isExpanded()) {
- mBubbleBarViewAnimator.animateBubbleInForStashed(bubble);
+ // only animate the new bubble if we're in an app, have handle view and not auto expanding
+ if (isInApp && mBubbleStashController.getHasHandleView() && !isExpanded()) {
+ mBubbleBarViewAnimator.animateBubbleInForStashed(bubble, isExpanding);
}
}
@@ -567,6 +627,7 @@
public void setExpanded(boolean isExpanded) {
if (isExpanded != mBarView.isExpanded()) {
mBarView.setExpanded(isExpanded);
+ updatePersistentTaskbar(isExpanded);
if (!isExpanded) {
mSystemUiProxy.collapseBubbles();
} else {
@@ -577,11 +638,34 @@
}
}
+ private void updatePersistentTaskbar(boolean isBubbleBarExpanded) {
+ if (mBubbleStashController.isTransientTaskBar()) return;
+ boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
+ mTaskbarViewPropertiesProvider
+ .getIconsAlpha()
+ .animateToValue(hideTaskbar ? 0 : 1)
+ .start();
+ }
+
+ /** Return {@code true} if expanded bubble bar would intersect the taskbar. */
+ public boolean isIntersectingTaskbar() {
+ if (mBarView.isExpanding() || mBarView.isExpanded()) {
+ Rect taskbarViewBounds = mTaskbarViewPropertiesProvider.getTaskbarViewBounds();
+ return mBarView.getBubbleBarExpandedBounds().intersect(taskbarViewBounds);
+ } else {
+ return false;
+ }
+ }
+
/**
* Sets whether the bubble bar should be expanded. This method is used in response to UI events
* from SystemUI.
*/
public void setExpandedFromSysui(boolean isExpanded) {
+ if (isNewBubbleAnimationRunningOrPending() && isExpanded) {
+ mBubbleBarViewAnimator.expandedWhileAnimating();
+ return;
+ }
if (!isExpanded) {
mBubbleStashController.stashBubbleBar();
} else {
@@ -598,6 +682,7 @@
/**
* Updates the dragged bubble view in the bubble bar view, and notifies SystemUI
* that a bubble is being dragged to dismiss.
+ *
* @param bubbleView dragged bubble view
*/
public void onBubbleDragStart(@NonNull BubbleView bubbleView) {
@@ -705,4 +790,14 @@
pw.println(" Bubble bar view is null!");
}
}
+
+ /** Interface for BubbleBarViewController to get the taskbar view properties. */
+ public interface TaskbarViewPropertiesProvider {
+
+ /** Returns the bounds of the taskbar. */
+ Rect getTaskbarViewBounds();
+
+ /** Returns taskbar icons alpha */
+ MultiPropertyFactory<View>.MultiProperty getIconsAlpha();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index 03140fe..e00916a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -15,24 +15,32 @@
*/
package com.android.launcher3.taskbar.bubbles;
+import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_BUBBLE_BAR;
+
+import android.graphics.Rect;
+import android.view.View;
+
import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController.TaskbarViewPropertiesProvider;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.RunnableList;
import java.io.PrintWriter;
+import java.util.Optional;
-/**
- * Hosts various bubble controllers to facilitate passing between one another.
- */
+/** Hosts various bubble controllers to facilitate passing between one another. */
public class BubbleControllers {
public final BubbleBarController bubbleBarController;
public final BubbleBarViewController bubbleBarViewController;
public final BubbleStashController bubbleStashController;
- public final BubbleStashedHandleViewController bubbleStashedHandleViewController;
+ public final Optional<BubbleStashedHandleViewController> bubbleStashedHandleViewController;
public final BubbleDragController bubbleDragController;
public final BubbleDismissController bubbleDismissController;
public final BubbleBarPinController bubbleBarPinController;
public final BubblePinController bubblePinController;
+ public final BubbleCreator bubbleCreator;
private final RunnableList mPostInitRunnables = new RunnableList();
@@ -45,11 +53,12 @@
BubbleBarController bubbleBarController,
BubbleBarViewController bubbleBarViewController,
BubbleStashController bubbleStashController,
- BubbleStashedHandleViewController bubbleStashedHandleViewController,
+ Optional<BubbleStashedHandleViewController> bubbleStashedHandleViewController,
BubbleDragController bubbleDragController,
BubbleDismissController bubbleDismissController,
BubbleBarPinController bubbleBarPinController,
- BubblePinController bubblePinController) {
+ BubblePinController bubblePinController,
+ BubbleCreator bubbleCreator) {
this.bubbleBarController = bubbleBarController;
this.bubbleBarViewController = bubbleBarViewController;
this.bubbleStashController = bubbleStashController;
@@ -58,6 +67,7 @@
this.bubbleDismissController = bubbleDismissController;
this.bubbleBarPinController = bubbleBarPinController;
this.bubblePinController = bubblePinController;
+ this.bubbleCreator = bubbleCreator;
}
/**
@@ -68,9 +78,28 @@
public void init(TaskbarControllers taskbarControllers) {
bubbleBarController.init(this,
taskbarControllers.navbarButtonsViewController::isImeVisible);
- bubbleBarViewController.init(taskbarControllers, this);
- bubbleStashedHandleViewController.init(taskbarControllers, this);
- bubbleStashController.init(taskbarControllers, this);
+ bubbleStashedHandleViewController.ifPresent(
+ controller -> controller.init(/* bubbleControllers = */ this));
+ bubbleStashController.init(
+ taskbarControllers.taskbarInsetsController,
+ bubbleBarViewController,
+ bubbleStashedHandleViewController.orElse(null),
+ taskbarControllers::runAfterInit
+ );
+ bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this,
+ new TaskbarViewPropertiesProvider() {
+ @Override
+ public Rect getTaskbarViewBounds() {
+ return taskbarControllers.taskbarViewController.getIconLayoutBounds();
+ }
+
+ @Override
+ public MultiPropertyFactory<View>.MultiProperty getIconsAlpha() {
+ return taskbarControllers.taskbarViewController
+ .getTaskbarIconAlpha()
+ .get(ALPHA_INDEX_BUBBLE_BAR);
+ }
+ });
bubbleDragController.init(/* bubbleControllers = */ this);
bubbleDismissController.init(/* bubbleControllers = */ this);
bubbleBarPinController.init(this);
@@ -93,7 +122,7 @@
* Cleans up all controllers.
*/
public void onDestroy() {
- bubbleStashedHandleViewController.onDestroy();
+ bubbleStashedHandleViewController.ifPresent(BubbleStashedHandleViewController::onDestroy);
bubbleBarController.onDestroy();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
new file mode 100644
index 0000000..8e9a2f6
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles;
+
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_PERSONS_DATA;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
+
+import static com.android.launcher3.icons.FastBitmapDrawable.WHITE_SCRIM_ALPHA;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.PathParser;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.appcompat.content.res.AppCompatResources;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.BubbleIconFactory;
+import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.wm.shell.common.bubbles.BubbleInfo;
+
+/**
+ * Loads the necessary info to populate / present a bubble (name, icon, shortcut).
+ */
+public class BubbleCreator {
+
+ private static final String TAG = BubbleCreator.class.getSimpleName();
+
+ private final Context mContext;
+ private final LauncherApps mLauncherApps;
+ private final BubbleIconFactory mIconFactory;
+
+ public BubbleCreator(Context context) {
+ mContext = context;
+ mLauncherApps = mContext.getSystemService(LauncherApps.class);
+ mIconFactory = new BubbleIconFactory(context,
+ context.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size),
+ context.getResources().getDimensionPixelSize(R.dimen.bubblebar_badge_size),
+ context.getResources().getColor(R.color.important_conversation),
+ context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.importance_ring_stroke_width));
+ }
+
+ /**
+ * Creates a BubbleBarBubble object, including the view if needed, and populates it with
+ * the info needed for presentation.
+ *
+ * @param context the context to use for inflation.
+ * @param info the info to use to populate the bubble.
+ * @param barView the parent view for the bubble (bubble is not added to the view).
+ * @param existingBubble if a bubble exists already, this object gets updated with the new
+ * info & returned (& any existing views are reused instead of inflating
+ * new ones.
+ */
+ @Nullable
+ public BubbleBarBubble populateBubble(Context context, BubbleInfo info, ViewGroup barView,
+ @Nullable BubbleBarBubble existingBubble) {
+ String appName;
+ Bitmap badgeBitmap;
+ Bitmap bubbleBitmap;
+ Path dotPath;
+ int dotColor;
+
+ boolean isImportantConvo = info.isImportantConversation();
+
+ ShortcutRequest.QueryResult result = new ShortcutRequest(context,
+ new UserHandle(info.getUserId()))
+ .forPackage(info.getPackageName(), info.getShortcutId())
+ .query(FLAG_MATCH_DYNAMIC
+ | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+ | FLAG_MATCH_CACHED
+ | FLAG_GET_PERSONS_DATA);
+
+ ShortcutInfo shortcutInfo = result.size() > 0 ? result.get(0) : null;
+ if (shortcutInfo == null) {
+ Log.w(TAG, "No shortcutInfo found for bubble: " + info.getKey()
+ + " with shortcutId: " + info.getShortcutId());
+ }
+
+ ApplicationInfo appInfo;
+ try {
+ appInfo = mLauncherApps.getApplicationInfo(
+ info.getPackageName(),
+ 0,
+ new UserHandle(info.getUserId()));
+ } catch (PackageManager.NameNotFoundException e) {
+ // If we can't find package... don't think we should show the bubble.
+ Log.w(TAG, "Unable to find packageName: " + info.getPackageName());
+ return null;
+ }
+ if (appInfo == null) {
+ Log.w(TAG, "Unable to find appInfo: " + info.getPackageName());
+ return null;
+ }
+ PackageManager pm = context.getPackageManager();
+ appName = String.valueOf(appInfo.loadLabel(pm));
+ Drawable appIcon = appInfo.loadUnbadgedIcon(pm);
+ Drawable badgedIcon = pm.getUserBadgedIcon(appIcon, new UserHandle(info.getUserId()));
+
+ // Badged bubble image
+ Drawable bubbleDrawable = mIconFactory.getBubbleDrawable(context, shortcutInfo,
+ info.getIcon());
+ if (bubbleDrawable == null) {
+ // Default to app icon
+ bubbleDrawable = appIcon;
+ }
+
+ BitmapInfo badgeBitmapInfo = mIconFactory.getBadgeBitmap(badgedIcon, isImportantConvo);
+ badgeBitmap = badgeBitmapInfo.icon;
+
+ float[] bubbleBitmapScale = new float[1];
+ bubbleBitmap = mIconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
+
+ // Dot color & placement
+ Path iconPath = PathParser.createPathFromPathData(
+ context.getResources().getString(
+ com.android.internal.R.string.config_icon_mask));
+ Matrix matrix = new Matrix();
+ float scale = bubbleBitmapScale[0];
+ float radius = BubbleView.DEFAULT_PATH_SIZE / 2f;
+ matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+ radius /* pivot y */);
+ iconPath.transform(matrix);
+ dotPath = iconPath;
+ dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
+ Color.WHITE, WHITE_SCRIM_ALPHA / 255f);
+
+ if (existingBubble == null) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ BubbleView bubbleView = (BubbleView) inflater.inflate(
+ R.layout.bubblebar_item_view, barView, false /* attachToRoot */);
+
+ BubbleBarBubble bubble = new BubbleBarBubble(info, bubbleView,
+ badgeBitmap, bubbleBitmap, dotColor, dotPath, appName);
+ bubbleView.setBubble(bubble);
+ return bubble;
+ } else {
+ // If we already have a bubble (so it already has an inflated view), update it.
+ existingBubble.setInfo(info);
+ existingBubble.setBadge(badgeBitmap);
+ existingBubble.setIcon(bubbleBitmap);
+ existingBubble.setDotColor(dotColor);
+ existingBubble.setDotPath(dotPath);
+ existingBubble.setAppName(appName);
+ return existingBubble;
+ }
+ }
+
+ /**
+ * Creates the overflow view shown in the bubble bar.
+ *
+ * @param barView the parent view for the bubble (bubble is not added to the view).
+ */
+ public BubbleBarOverflow createOverflow(ViewGroup barView) {
+ Bitmap bitmap = createOverflowBitmap();
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ BubbleView bubbleView = (BubbleView) inflater.inflate(
+ R.layout.bubble_bar_overflow_button, barView, false /* attachToRoot */);
+ BubbleBarOverflow overflow = new BubbleBarOverflow(bubbleView);
+ bubbleView.setOverflow(overflow, bitmap);
+ return overflow;
+ }
+
+ private Bitmap createOverflowBitmap() {
+ Drawable iconDrawable = AppCompatResources.getDrawable(mContext,
+ R.drawable.bubble_ic_overflow_button);
+
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ new int[]{
+ R.attr.materialColorOnPrimaryFixed,
+ R.attr.materialColorPrimaryFixed
+ });
+ int overflowIconColor = ta.getColor(0, Color.WHITE);
+ int overflowBackgroundColor = ta.getColor(1, Color.BLACK);
+ ta.recycle();
+
+ iconDrawable.setTint(overflowIconColor);
+
+ int inset = mContext.getResources().getDimensionPixelSize(R.dimen.bubblebar_overflow_inset);
+ Drawable foreground = new InsetDrawable(iconDrawable, inset);
+ Drawable drawable = new AdaptiveIconDrawable(new ColorDrawable(overflowBackgroundColor),
+ foreground);
+
+ return mIconFactory.createBadgedIconBitmap(drawable).icon;
+ }
+
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 7aed2d2..87f466f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -128,7 +128,7 @@
boolean wasFling, boolean canceled, float finalValue, float finalVelocity,
boolean allRelevantPropertyAnimationsEnded) -> {
if (canceled || allRelevantPropertyAnimationsEnded) {
- resetAnimatedViews(restingPosition);
+ resetAnimatedViews(restingPosition, /* dismissed= */ false);
if (endActions != null) {
endActions.run();
}
@@ -197,7 +197,7 @@
boolean wasFling, boolean canceled, float finalValue, float finalVelocity,
boolean allRelevantPropertyAnimationsEnded) -> {
if (canceled || allRelevantPropertyAnimationsEnded) {
- resetAnimatedViews(initialPosition);
+ resetAnimatedViews(initialPosition, /* dismissed= */ true);
if (endActions != null) endActions.run();
}
})
@@ -208,11 +208,14 @@
* Reset the animated views to the initial state
*
* @param initialPosition position of the bubble
+ * @param dismissed whether the animated view was dismissed
*/
- private void resetAnimatedViews(@NonNull PointF initialPosition) {
+ private void resetAnimatedViews(@NonNull PointF initialPosition, boolean dismissed) {
mView.setScaleX(1f);
mView.setScaleY(1f);
- mView.setAlpha(1f);
+ if (!dismissed) {
+ mView.setAlpha(1f);
+ }
mView.setTranslationX(initialPosition.x);
mView.setTranslationY(initialPosition.y);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
index a77e685..1341b53 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
@@ -27,6 +27,7 @@
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.common.bubbles.BaseBubblePinController
import com.android.wm.shell.common.bubbles.BubbleBarLocation
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
deleted file mode 100644
index 74f58ac..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar.bubbles;
-
-import static java.lang.Math.abs;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.annotation.Nullable;
-import android.view.InsetsController;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimatedFloat;
-import com.android.launcher3.taskbar.StashedHandleViewController;
-import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.taskbar.TaskbarControllers;
-import com.android.launcher3.taskbar.TaskbarInsetsController;
-import com.android.launcher3.taskbar.TaskbarStashController;
-import com.android.launcher3.util.MultiPropertyFactory;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.shared.animation.PhysicsAnimator;
-
-import java.io.PrintWriter;
-
-/**
- * Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
- * create a cohesive animation between stashed/unstashed states.
- */
-public class BubbleStashController {
-
- private static final String TAG = "BubbleStashController";
-
- /**
- * How long to stash/unstash.
- */
- public static final long BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
-
- /**
- * The scale bubble bar animates to when being stashed.
- */
- private static final float STASHED_BAR_SCALE = 0.5f;
-
- protected final TaskbarActivityContext mActivity;
-
- // Initialized in init.
- private TaskbarControllers mControllers;
- private TaskbarInsetsController mTaskbarInsetsController;
- private BubbleBarViewController mBarViewController;
- private BubbleStashedHandleViewController mHandleViewController;
- private TaskbarStashController mTaskbarStashController;
-
- private MultiPropertyFactory.MultiProperty mIconAlphaForStash;
- private AnimatedFloat mIconScaleForStash;
- private AnimatedFloat mIconTranslationYForStash;
- private MultiPropertyFactory.MultiProperty mBubbleStashedHandleAlpha;
-
- private boolean mRequestedStashState;
- private boolean mRequestedExpandedState;
-
- private boolean mIsStashed;
- private int mStashedHeight;
- private int mUnstashedHeight;
- private boolean mBubblesShowingOnHome;
- private boolean mBubblesShowingOnOverview;
- private boolean mIsSysuiLocked;
-
- private final float mHandleCenterFromScreenBottom;
-
- @Nullable
- private AnimatorSet mAnimator;
-
- public BubbleStashController(TaskbarActivityContext activity) {
- mActivity = activity;
- // the handle is centered within the stashed taskbar area
- mHandleCenterFromScreenBottom =
- mActivity.getResources().getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f;
- }
-
- public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
- mControllers = controllers;
- mTaskbarInsetsController = controllers.taskbarInsetsController;
- mBarViewController = bubbleControllers.bubbleBarViewController;
- mHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
- mTaskbarStashController = controllers.taskbarStashController;
-
- mIconAlphaForStash = mBarViewController.getBubbleBarAlpha().get(0);
- mIconScaleForStash = mBarViewController.getBubbleBarScale();
- mIconTranslationYForStash = mBarViewController.getBubbleBarTranslationY();
-
- mBubbleStashedHandleAlpha = mHandleViewController.getStashedHandleAlpha().get(
- StashedHandleViewController.ALPHA_INDEX_STASHED);
-
- mStashedHeight = mHandleViewController.getStashedHeight();
- mUnstashedHeight = mHandleViewController.getUnstashedHeight();
- }
-
- /**
- * Returns the touchable height of the bubble bar based on it's stashed state.
- */
- public int getTouchableHeight() {
- return mIsStashed ? mStashedHeight : mUnstashedHeight;
- }
-
- /**
- * Returns whether the bubble bar is currently stashed.
- */
- public boolean isStashed() {
- return mIsStashed;
- }
-
- /**
- * Animates the handle (or bubble bar depending on state) to be visible after the device is
- * unlocked.
- *
- * <p>Normally either the bubble bar or the handle is visible,
- * and {@link #showBubbleBar(boolean)} and {@link #stashBubbleBar()} are used to transition
- * between these two states. But the transition from the state where both the bar and handle
- * are invisible is slightly different.
- */
- private void animateAfterUnlock() {
- AnimatorSet animatorSet = new AnimatorSet();
- if (mBubblesShowingOnHome || mBubblesShowingOnOverview) {
- mIsStashed = false;
- animatorSet.playTogether(mIconScaleForStash.animateToValue(1),
- mIconTranslationYForStash.animateToValue(getBubbleBarTranslationY()),
- mIconAlphaForStash.animateToValue(1));
- } else {
- mIsStashed = true;
- animatorSet.playTogether(mBubbleStashedHandleAlpha.animateToValue(1));
- }
-
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- onIsStashedChanged();
- }
- });
- animatorSet.setDuration(BAR_STASH_DURATION).start();
- }
-
- /**
- * Called when launcher enters or exits the home page. Bubbles are unstashed on home.
- */
- public void setBubblesShowingOnHome(boolean onHome) {
- if (mBubblesShowingOnHome != onHome) {
- mBubblesShowingOnHome = onHome;
-
- if (!mBarViewController.hasBubbles()) {
- // if there are no bubbles, there's nothing to show, so just return.
- return;
- }
-
- if (mBubblesShowingOnHome) {
- showBubbleBar(/* expanded= */ false);
- // When transitioning from app to home the stash animator may already have been
- // created, so we need to animate the bubble bar here to align with hotseat.
- if (!mIsStashed) {
- mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForHotseat())
- .start();
- }
- // If the bubble bar is already unstashed, the taskbar touchable region won't be
- // updated correctly, so force an update here.
- mControllers.runAfterInit(() ->
- mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged());
- } else if (!mBarViewController.isExpanded()) {
- stashBubbleBar();
- }
- }
- }
-
- /** Whether bubbles are showing on the launcher home page. */
- public boolean isBubblesShowingOnHome() {
- boolean hasBubbles = mBarViewController != null && mBarViewController.hasBubbles();
- return mBubblesShowingOnHome && hasBubbles;
- }
-
- // TODO: when tapping on an app in overview, this is a bit delayed compared to taskbar stashing
- /** Called when launcher enters or exits overview. Bubbles are unstashed on overview. */
- public void setBubblesShowingOnOverview(boolean onOverview) {
- if (mBubblesShowingOnOverview != onOverview) {
- mBubblesShowingOnOverview = onOverview;
- if (!mBubblesShowingOnOverview && !mBarViewController.isExpanded()) {
- stashBubbleBar();
- } else {
- // When transitioning to overview the stash animator may already have been
- // created, so we need to animate the bubble bar here to align with taskbar.
- mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForTaskbar())
- .start();
- }
- }
- }
-
- /** Whether bubbles are showing on Overview. */
- public boolean isBubblesShowingOnOverview() {
- return mBubblesShowingOnOverview;
- }
-
- /** Called when sysui locked state changes, when locked, bubble bar is stashed. */
- public void onSysuiLockedStateChange(boolean isSysuiLocked) {
- if (isSysuiLocked != mIsSysuiLocked) {
- mIsSysuiLocked = isSysuiLocked;
- if (!mIsSysuiLocked && mBarViewController.hasBubbles()) {
- animateAfterUnlock();
- }
- }
- }
-
- /**
- * Stashes the bubble bar if allowed based on other state (e.g. on home and overview the
- * bar does not stash).
- */
- public void stashBubbleBar() {
- mRequestedStashState = true;
- mRequestedExpandedState = false;
- updateStashedAndExpandedState();
- }
-
- /**
- * Shows the bubble bar, and expands bubbles depending on {@param expandBubbles}.
- */
- public void showBubbleBar(boolean expandBubbles) {
- mRequestedStashState = false;
- mRequestedExpandedState = expandBubbles;
- updateStashedAndExpandedState();
- }
-
- private void updateStashedAndExpandedState() {
- if (mBarViewController.isHiddenForNoBubbles()) {
- // If there are no bubbles the bar and handle are invisible, nothing to do here.
- return;
- }
- boolean isStashed = mRequestedStashState
- && !mBubblesShowingOnHome
- && !mBubblesShowingOnOverview;
- if (mIsStashed != isStashed) {
- // notify the view controller that the stash state is about to change so that it can
- // cancel an ongoing animation if there is one.
- // note that this has to be called before updating mIsStashed with the new value,
- // otherwise interrupting an ongoing animation may update it again with the wrong state
- mBarViewController.onStashStateChanging();
- mIsStashed = isStashed;
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- mAnimator = createStashAnimator(mIsStashed, BAR_STASH_DURATION);
- mAnimator.start();
- onIsStashedChanged();
- }
- if (mBarViewController.isExpanded() != mRequestedExpandedState) {
- mBarViewController.setExpanded(mRequestedExpandedState);
- }
- }
-
- /**
- * Create a stash animation.
- *
- * @param isStashed whether it's a stash animation or an unstash animation
- * @param duration duration of the animation
- * @return the animation
- */
- private AnimatorSet createStashAnimator(boolean isStashed, long duration) {
- AnimatorSet animatorSet = new AnimatorSet();
-
- AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
- // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
- AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
- AnimatorSet secondHalfAnimatorSet = new AnimatorSet();
-
- final float firstHalfDurationScale;
- final float secondHalfDurationScale;
-
- if (isStashed) {
- firstHalfDurationScale = 0.75f;
- secondHalfDurationScale = 0.5f;
-
- fullLengthAnimatorSet.play(
- mIconTranslationYForStash.animateToValue(getStashTranslation()));
-
- firstHalfAnimatorSet.playTogether(
- mIconAlphaForStash.animateToValue(0),
- mIconScaleForStash.animateToValue(STASHED_BAR_SCALE));
- secondHalfAnimatorSet.playTogether(
- mBubbleStashedHandleAlpha.animateToValue(1));
- } else {
- firstHalfDurationScale = 0.5f;
- secondHalfDurationScale = 0.75f;
-
- final float translationY = getBubbleBarTranslationY();
-
- fullLengthAnimatorSet.playTogether(
- mIconScaleForStash.animateToValue(1),
- mIconTranslationYForStash.animateToValue(translationY));
-
- firstHalfAnimatorSet.playTogether(
- mBubbleStashedHandleAlpha.animateToValue(0)
- );
- secondHalfAnimatorSet.playTogether(
- mIconAlphaForStash.animateToValue(1)
- );
- }
-
- fullLengthAnimatorSet.play(mHandleViewController.createRevealAnimToIsStashed(isStashed));
-
- fullLengthAnimatorSet.setDuration(duration);
- firstHalfAnimatorSet.setDuration((long) (duration * firstHalfDurationScale));
- secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale));
- secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale)));
-
- animatorSet.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
- secondHalfAnimatorSet);
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
- mControllers.runAfterInit(() -> {
- if (isStashed) {
- mBarViewController.setExpanded(false);
- }
- mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
- });
- }
- });
- return animatorSet;
- }
-
- private float getStashTranslation() {
- return (mUnstashedHeight - mStashedHeight) / 2f;
- }
-
- private void onIsStashedChanged() {
- mControllers.runAfterInit(() -> {
- mHandleViewController.onIsStashedChanged();
- mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
- });
- }
-
- public float getBubbleBarTranslationYForTaskbar() {
- return -mActivity.getDeviceProfile().taskbarBottomMargin;
- }
-
- private float getBubbleBarTranslationYForHotseat() {
- final float hotseatBottomSpace = mActivity.getDeviceProfile().hotseatBarBottomSpacePx;
- final float hotseatCellHeight = mActivity.getDeviceProfile().hotseatCellHeightPx;
- return -hotseatBottomSpace - hotseatCellHeight + mUnstashedHeight - abs(
- hotseatCellHeight - mUnstashedHeight) / 2;
- }
-
- public float getBubbleBarTranslationY() {
- // If we're on home, adjust the translation so the bubble bar aligns with hotseat.
- // Otherwise we're either showing in an app or in overview. In either case adjust it so
- // the bubble bar aligns with the taskbar.
- return mBubblesShowingOnHome ? getBubbleBarTranslationYForHotseat()
- : getBubbleBarTranslationYForTaskbar();
- }
-
- /**
- * The difference on the Y axis between the center of the handle and the center of the bubble
- * bar.
- */
- public float getDiffBetweenHandleAndBarCenters() {
- // the difference between the centers of the handle and the bubble bar is the difference
- // between their distance from the bottom of the screen.
-
- float barCenter = mBarViewController.getBubbleBarCollapsedHeight() / 2f;
- return mHandleCenterFromScreenBottom - barCenter;
- }
-
- /** The distance the handle moves as part of the new bubble animation. */
- public float getStashedHandleTranslationForNewBubbleAnimation() {
- // the should move up to the top of the stashed taskbar area. it is centered within it so
- // it should move the same distance as it is away from the bottom.
- return -mHandleCenterFromScreenBottom;
- }
-
- /** Checks whether the motion event is over the stash handle. */
- public boolean isEventOverStashHandle(MotionEvent ev) {
- return mHandleViewController.isEventOverHandle(ev);
- }
-
- /** Set a bubble bar location */
- public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
- mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
- }
-
- /** Returns the [PhysicsAnimator] for the stashed handle view. */
- public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
- return mHandleViewController.getPhysicsAnimator();
- }
-
- /** Notifies taskbar that it should update its touchable region. */
- public void updateTaskbarTouchRegion() {
- mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
- }
-
- /** Shows the bubble bar immediately without animation. */
- public void showBubbleBarImmediate() {
- mHandleViewController.setTranslationYForSwipe(0);
- mIconTranslationYForStash.updateValue(getBubbleBarTranslationY());
- mIconAlphaForStash.setValue(1);
- mIconScaleForStash.updateValue(1);
- mIsStashed = false;
- onIsStashedChanged();
- }
-
- /** Stashes the bubble bar immediately without animation. */
- public void stashBubbleBarImmediate() {
- mHandleViewController.setTranslationYForSwipe(0);
- mBubbleStashedHandleAlpha.setValue(1);
- mIconAlphaForStash.setValue(0);
- mIconTranslationYForStash.updateValue(getStashTranslation());
- mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
- mIsStashed = true;
- onIsStashedChanged();
- }
-
- /**
- * Updates the values of the internal animators after the new bubble animation was interrupted
- *
- * @param isStashed whether the current state should be stashed
- * @param bubbleBarTranslationY the current bubble bar translation. this is only used if the
- * bubble bar is showing to ensure that the stash animator runs
- * smoothly.
- */
- public void onNewBubbleAnimationInterrupted(boolean isStashed, float bubbleBarTranslationY) {
- if (isStashed) {
- mBubbleStashedHandleAlpha.setValue(1);
- mIconAlphaForStash.setValue(0);
- mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
- mIconTranslationYForStash.updateValue(getStashTranslation());
- } else {
- mBubbleStashedHandleAlpha.setValue(0);
- mHandleViewController.setTranslationYForSwipe(0);
- mIconAlphaForStash.setValue(1);
- mIconScaleForStash.updateValue(1);
- mIconTranslationYForStash.updateValue(bubbleBarTranslationY);
- }
- mIsStashed = isStashed;
- onIsStashedChanged();
- }
-
- /** Set the translation Y for the stashed handle. */
- public void setHandleTranslationY(float ty) {
- mHandleViewController.setTranslationYForSwipe(ty);
- }
-
- /** Dumps the state of BubbleStashController. */
- public void dump(PrintWriter pw) {
- pw.println("Bubble stash controller state:");
- pw.println(" mIsStashed: " + mIsStashed);
- pw.println(" mBubblesShowingOnOverview: " + mBubblesShowingOnOverview);
- pw.println(" mBubblesShowingOnHome: " + mBubblesShowingOnHome);
- pw.println(" mIsSysuiLocked: " + mIsSysuiLocked);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 91103d7..8158fe7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -33,7 +33,7 @@
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.taskbar.StashedHandleView;
import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
@@ -79,7 +79,8 @@
mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
}
- public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
+ /** Initialize controller. */
+ public void init(BubbleControllers bubbleControllers) {
mBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleStashController = bubbleControllers.bubbleStashController;
@@ -117,7 +118,7 @@
public Rect getSampledRegion(View sampledView) {
return mStashedHandleView.getSampledRegion();
}
- }, Executors.UI_HELPER_EXECUTOR);
+ }, Executors.MAIN_EXECUTOR, Executors.UI_HELPER_EXECUTOR);
mStashedHandleView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
updateBounds(mBarViewController.getBubbleBarLocation()));
@@ -244,6 +245,11 @@
mStashedHandleView.setTranslationY(transY);
}
+ /** Returns the translation of the stashed handle. */
+ public float getTranslationY() {
+ return mStashedHandleView.getTranslationY();
+ }
+
/**
* Used by {@link BubbleStashController} to animate the handle when stashing or un stashing.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 739be9e..eb3b24b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -74,6 +74,7 @@
private boolean mOnLeft = false;
private BubbleBarItem mBubble;
+ private boolean mIsOverflow;
private Bitmap mIcon;
@@ -271,12 +272,18 @@
*/
public void setOverflow(BubbleBarOverflow overflow, Bitmap bitmap) {
mBubble = overflow;
+ mIsOverflow = true;
mIcon = bitmap;
updateBubbleIcon();
mAppIcon.setVisibility(GONE); // Overflow doesn't show the app badge
setContentDescription(getResources().getString(R.string.bubble_bar_overflow_description));
}
+ /** Whether this view represents the overflow button. */
+ public boolean isOverflow() {
+ return mIsOverflow;
+ }
+
/** Returns the bubble being rendered in this view. */
@Nullable
public BubbleBarItem getBubble() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index feff9fd..2ed88d8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -26,8 +26,8 @@
import com.android.launcher3.R
import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
import com.android.launcher3.taskbar.bubbles.BubbleBarView
-import com.android.launcher3.taskbar.bubbles.BubbleStashController
import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.shared.animation.PhysicsAnimator
/** Handles animations for bubble bar bubbles. */
@@ -43,6 +43,14 @@
private val bubbleBarBounceDistanceInPx =
bubbleBarView.resources.getDimensionPixelSize(R.dimen.bubblebar_bounce_distance)
+ fun hasAnimation() = animatingBubble != null
+
+ val isAnimating: Boolean
+ get() {
+ val animatingBubble = animatingBubble ?: return false
+ return animatingBubble.state != AnimatingBubble.State.CREATED
+ }
+
private companion object {
/** The time to show the flyout. */
const val FLYOUT_DELAY_MS: Long = 2500
@@ -58,8 +66,33 @@
private data class AnimatingBubble(
val bubbleView: BubbleView,
val showAnimation: Runnable,
- val hideAnimation: Runnable
- )
+ val hideAnimation: Runnable,
+ val expand: Boolean,
+ val state: State = State.CREATED
+ ) {
+
+ /**
+ * The state of the animation.
+ *
+ * The animation is initially created but will be scheduled later using the [Scheduler].
+ *
+ * The normal uninterrupted cycle is for the bubble notification to animate in, then be in a
+ * transient state and eventually to animate out.
+ *
+ * However different events, such as touch and external signals, may cause the animation to
+ * end earlier.
+ */
+ enum class State {
+ /** The animation is created but not started yet. */
+ CREATED,
+ /** The bubble notification is animating in. */
+ ANIMATING_IN,
+ /** The bubble notification is now fully showing and waiting to be hidden. */
+ IN,
+ /** The bubble notification is animating out. */
+ ANIMATING_OUT
+ }
+ }
/** An interface for scheduling jobs. */
interface Scheduler {
@@ -97,15 +130,18 @@
)
/** Animates a bubble for the state where the bubble bar is stashed. */
- fun animateBubbleInForStashed(b: BubbleBarBubble) {
+ fun animateBubbleInForStashed(b: BubbleBarBubble, isExpanding: Boolean) {
+ // TODO b/346400677: handle animations for the same bubble interrupting each other
+ if (animatingBubble?.bubbleView?.bubble?.key == b.key) return
val bubbleView = b.view
val animator = PhysicsAnimator.getInstance(bubbleView)
if (animator.isRunning()) animator.cancel()
// the animation of a new bubble is divided into 2 parts. The first part shows the bubble
// and the second part hides it after a delay.
val showAnimation = buildHandleToBubbleBarAnimation()
- val hideAnimation = buildBubbleBarToHandleAnimation()
- animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+ val hideAnimation = if (isExpanding) Runnable {} else buildBubbleBarToHandleAnimation()
+ animatingBubble =
+ AnimatingBubble(bubbleView, showAnimation, hideAnimation, expand = isExpanding)
scheduler.post(showAnimation)
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
}
@@ -125,8 +161,8 @@
* visible which helps avoiding further updates when we re-enter the second part.
*/
private fun buildHandleToBubbleBarAnimation() = Runnable {
+ moveToState(AnimatingBubble.State.ANIMATING_IN)
// prepare the bubble bar for the animation
- bubbleBarView.onAnimatingBubbleStarted()
bubbleBarView.visibility = VISIBLE
bubbleBarView.alpha = 0f
bubbleBarView.translationY = 0f
@@ -138,26 +174,29 @@
// handle. when the handle becomes invisible and we start animating in the bubble bar,
// the translation y is offset by this value to make the transition from the handle to the
// bar smooth.
- val offset = bubbleStashController.diffBetweenHandleAndBarCenters
+ val offset = bubbleStashController.getDiffBetweenHandleAndBarCenters()
+ val stashedHandleTranslationYForAnimation =
+ bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation()
val stashedHandleTranslationY =
- bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
+ bubbleStashController.getHandleTranslationY() ?: return@Runnable
+ val translationTracker = TranslationTracker(stashedHandleTranslationY)
// this is the total distance that both the stashed handle and the bubble will be traveling
// at the end of the animation the bubble bar will be positioned in the same place when it
// shows while we're in an app.
val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
- val animator = bubbleStashController.stashedHandlePhysicsAnimator
+ val animator = bubbleStashController.getStashedHandlePhysicsAnimator() ?: return@Runnable
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, totalTranslationY)
animator.addUpdateListener { handle, values ->
val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
when {
- ty >= stashedHandleTranslationY -> {
+ ty >= stashedHandleTranslationYForAnimation -> {
// we're in the first leg of the animation. only animate the handle. the bubble
// bar remains hidden during this part of the animation
// map the path [0, stashedHandleTranslationY] to [0,1]
- val fraction = ty / stashedHandleTranslationY
+ val fraction = ty / stashedHandleTranslationYForAnimation
handle.alpha = 1 - fraction
}
ty >= totalTranslationY -> {
@@ -171,8 +210,8 @@
if (bubbleBarView.alpha != 1f) {
// map the path [stashedHandleTranslationY, totalTranslationY] to [0, 1]
val fraction =
- (ty - stashedHandleTranslationY) /
- (totalTranslationY - stashedHandleTranslationY)
+ (ty - stashedHandleTranslationYForAnimation) /
+ (totalTranslationY - stashedHandleTranslationYForAnimation)
bubbleBarView.alpha = fraction
bubbleBarView.scaleY =
BUBBLE_ANIMATION_INITIAL_SCALE_Y +
@@ -192,18 +231,16 @@
bubbleStashController.updateTaskbarTouchRegion()
}
}
+ translationTracker.updateTyAndExpandIfNeeded(ty)
}
animator.addEndListener { _, _, _, canceled, _, _, _ ->
// if the show animation was canceled, also cancel the hide animation. this is typically
// canceled in this class, but could potentially be canceled elsewhere.
- if (canceled) {
- val hideAnimation = animatingBubble?.hideAnimation ?: return@addEndListener
- scheduler.cancel(hideAnimation)
- animatingBubble = null
- bubbleBarView.onAnimatingBubbleCompleted()
- bubbleBarView.relativePivotY = 1f
+ if (canceled || animatingBubble?.expand == true) {
+ cancelHideAnimation()
return@addEndListener
}
+ moveToState(AnimatingBubble.State.IN)
// the bubble bar is now fully settled in. update taskbar touch region so it's touchable
bubbleStashController.updateTaskbarTouchRegion()
}
@@ -226,13 +263,14 @@
*/
private fun buildBubbleBarToHandleAnimation() = Runnable {
if (animatingBubble == null) return@Runnable
- val offset = bubbleStashController.diffBetweenHandleAndBarCenters
+ moveToState(AnimatingBubble.State.ANIMATING_OUT)
+ val offset = bubbleStashController.getDiffBetweenHandleAndBarCenters()
val stashedHandleTranslationY =
- bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
+ bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation()
// this is the total distance that both the stashed handle and the bar will be traveling
val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
bubbleStashController.setHandleTranslationY(totalTranslationY)
- val animator = bubbleStashController.stashedHandlePhysicsAnimator
+ val animator = bubbleStashController.getStashedHandlePhysicsAnimator() ?: return@Runnable
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
animator.addUpdateListener { handle, values ->
@@ -271,7 +309,6 @@
animator.addEndListener { _, _, _, canceled, _, _, _ ->
animatingBubble = null
if (!canceled) bubbleStashController.stashBubbleBarImmediate()
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleBarView.relativePivotY = 1f
bubbleStashController.updateTaskbarTouchRegion()
}
@@ -280,6 +317,8 @@
/** Animates to the initial state of the bubble bar, when there are no previous bubbles. */
fun animateToInitialState(b: BubbleBarBubble, isInApp: Boolean, isExpanding: Boolean) {
+ // TODO b/346400677: handle animations for the same bubble interrupting each other
+ if (animatingBubble?.bubbleView?.bubble?.key == b.key) return
val bubbleView = b.view
val animator = PhysicsAnimator.getInstance(bubbleView)
if (animator.isRunning()) animator.cancel()
@@ -295,36 +334,49 @@
Runnable {
animatingBubble = null
bubbleStashController.showBubbleBarImmediate()
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleStashController.updateTaskbarTouchRegion()
}
}
- animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+ animatingBubble =
+ AnimatingBubble(bubbleView, showAnimation, hideAnimation, expand = isExpanding)
scheduler.post(showAnimation)
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
}
private fun buildBubbleBarSpringInAnimation() = Runnable {
+ moveToState(AnimatingBubble.State.ANIMATING_IN)
// prepare the bubble bar for the animation
- bubbleBarView.onAnimatingBubbleStarted()
bubbleBarView.translationY = bubbleBarView.height.toFloat()
bubbleBarView.visibility = VISIBLE
bubbleBarView.alpha = 1f
bubbleBarView.scaleX = 1f
bubbleBarView.scaleY = 1f
+ val translationTracker = TranslationTracker(bubbleBarView.translationY)
+
val animator = PhysicsAnimator.getInstance(bubbleBarView)
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, bubbleStashController.bubbleBarTranslationY)
- animator.addUpdateListener { _, _ -> bubbleStashController.updateTaskbarTouchRegion() }
+ animator.addUpdateListener { _, values ->
+ val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+ translationTracker.updateTyAndExpandIfNeeded(ty)
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
animator.addEndListener { _, _, _, _, _, _, _ ->
+ if (animatingBubble?.expand == true) {
+ cancelHideAnimation()
+ } else {
+ moveToState(AnimatingBubble.State.IN)
+ }
// the bubble bar is now fully settled in. update taskbar touch region so it's touchable
bubbleStashController.updateTaskbarTouchRegion()
}
animator.start()
}
- fun animateBubbleBarForCollapsed(b: BubbleBarBubble) {
+ fun animateBubbleBarForCollapsed(b: BubbleBarBubble, isExpanding: Boolean) {
+ // TODO b/346400677: handle animations for the same bubble interrupting each other
+ if (animatingBubble?.bubbleView?.bubble?.key == b.key) return
val bubbleView = b.view
val animator = PhysicsAnimator.getInstance(bubbleView)
if (animator.isRunning()) animator.cancel()
@@ -332,10 +384,10 @@
val hideAnimation = Runnable {
animatingBubble = null
bubbleStashController.showBubbleBarImmediate()
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleStashController.updateTaskbarTouchRegion()
}
- animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+ animatingBubble =
+ AnimatingBubble(bubbleView, showAnimation, hideAnimation, expand = isExpanding)
scheduler.post(showAnimation)
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
}
@@ -346,27 +398,37 @@
* the bubble bar moves back to its initial position with a spring animation.
*/
private fun buildBubbleBarBounceAnimation() = Runnable {
- bubbleBarView.onAnimatingBubbleStarted()
+ moveToState(AnimatingBubble.State.ANIMATING_IN)
val ty = bubbleStashController.bubbleBarTranslationY
val springBackAnimation = PhysicsAnimator.getInstance(bubbleBarView)
springBackAnimation.setDefaultSpringConfig(springConfig)
springBackAnimation.spring(DynamicAnimation.TRANSLATION_Y, ty)
+ springBackAnimation.addEndListener { _, _, _, _, _, _, _ ->
+ if (animatingBubble?.expand == true) {
+ bubbleBarView.isExpanded = true
+ cancelHideAnimation()
+ } else {
+ moveToState(AnimatingBubble.State.IN)
+ }
+ }
// animate the bubble bar up and start the spring back down animation when it ends.
ObjectAnimator.ofFloat(bubbleBarView, View.TRANSLATION_Y, ty - bubbleBarBounceDistanceInPx)
.withDuration(BUBBLE_BAR_BOUNCE_ANIMATION_DURATION_MS)
- .withEndAction { springBackAnimation.start() }
+ .withEndAction {
+ if (animatingBubble?.expand == true) bubbleBarView.isExpanded = true
+ springBackAnimation.start()
+ }
.start()
}
/** Handles touching the animating bubble bar. */
fun onBubbleBarTouchedWhileAnimating() {
PhysicsAnimator.getInstance(bubbleBarView).cancelIfRunning()
- bubbleStashController.stashedHandlePhysicsAnimator.cancelIfRunning()
+ bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleBarView.relativePivotY = 1f
animatingBubble = null
}
@@ -376,8 +438,7 @@
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
animatingBubble = null
- bubbleStashController.stashedHandlePhysicsAnimator.cancel()
- bubbleBarView.onAnimatingBubbleCompleted()
+ bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
bubbleBarView.relativePivotY = 1f
bubbleStashController.onNewBubbleAnimationInterrupted(
/* isStashed= */ bubbleBarView.alpha == 0f,
@@ -385,8 +446,26 @@
)
}
- private fun <T> PhysicsAnimator<T>.cancelIfRunning() {
- if (isRunning()) cancel()
+ fun expandedWhileAnimating() {
+ val animatingBubble = animatingBubble ?: return
+ this.animatingBubble = animatingBubble.copy(expand = true)
+ // if we're fully in and waiting to hide, cancel the hide animation and clean up
+ if (animatingBubble.state == AnimatingBubble.State.IN) {
+ bubbleBarView.isExpanded = true
+ cancelHideAnimation()
+ }
+ }
+
+ private fun cancelHideAnimation() {
+ val hideAnimation = animatingBubble?.hideAnimation ?: return
+ scheduler.cancel(hideAnimation)
+ animatingBubble = null
+ bubbleBarView.relativePivotY = 1f
+ bubbleStashController.showBubbleBarImmediate()
+ }
+
+ private fun <T> PhysicsAnimator<T>?.cancelIfRunning() {
+ if (this?.isRunning() == true) cancel()
}
private fun ObjectAnimator.withDuration(duration: Long): ObjectAnimator {
@@ -404,4 +483,37 @@
)
return this
}
+
+ private fun moveToState(state: AnimatingBubble.State) {
+ val animatingBubble = this.animatingBubble ?: return
+ this.animatingBubble = animatingBubble.copy(state = state)
+ }
+
+ /**
+ * Tracks the translation Y of the bubble bar during the animation. When the bubble bar expands
+ * as part of the animation, the expansion should start after the bubble bar reaches the peak
+ * position.
+ */
+ private inner class TranslationTracker(initialTy: Float) {
+ private var previousTy = initialTy
+ private var startedExpanding = false
+ private var reachedPeak = false
+
+ fun updateTyAndExpandIfNeeded(ty: Float) {
+ if (!reachedPeak) {
+ // the bubble bar is positioned at the bottom of the screen and moves up using
+ // negative ty values. the peak is reached the first time we see a value that is
+ // greater than the previous.
+ if (ty > previousTy) {
+ reachedPeak = true
+ }
+ }
+ val expand = animatingBubble?.expand ?: false
+ if (reachedPeak && expand && !startedExpanding) {
+ bubbleBarView.isExpanded = true
+ startedExpanding = true
+ }
+ previousTy = ty
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index 59fc76c..48eb7de 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -52,7 +52,7 @@
/** Execute passed action only after controllers are initiated. */
interface ControllersAfterInitAction {
/** Execute action after controllers are initiated. */
- fun runAfterInit(action: () -> Unit)
+ fun runAfterInit(action: Runnable)
}
/** Whether bubble bar is currently stashed */
@@ -143,6 +143,9 @@
/** Set the translation Y for the stashed handle. */
fun setHandleTranslationY(translationY: Float)
+ /** Returns the translation of the handle. */
+ fun getHandleTranslationY(): Float?
+
/**
* Returns bubble bar Y position according to [isBubblesShowingOnHome] and
* [isBubblesShowingOnOverview] values. Default implementation only analyse
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt
new file mode 100644
index 0000000..a55763b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.stashing
+
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
+
+/**
+ * Implementation of the [TaskbarHotseatDimensionsProvider] that take sizes from the
+ * [DeviceProfile].
+ */
+class DeviceProfileDimensionsProviderAdapter(
+ private val taskbarActivityContext: TaskbarActivityContext
+) : TaskbarHotseatDimensionsProvider {
+ override fun getTaskbarBottomSpace(): Int = deviceProfile().taskbarBottomMargin
+
+ override fun getTaskbarHeight(): Int = deviceProfile().taskbarHeight
+
+ override fun getHotseatBottomSpace(): Int = deviceProfile().hotseatBarBottomSpacePx
+
+ override fun getHotseatHeight(): Int = deviceProfile().hotseatCellHeightPx
+
+ private fun deviceProfile(): DeviceProfile = taskbarActivityContext.deviceProfile
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index 62fe221..1b65019 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -198,6 +198,8 @@
// no op since does not have a handle view
}
+ override fun getHandleTranslationY(): Float? = null
+
private fun updateExpandedState(expand: Boolean) {
if (bubbleBarViewController.isHiddenForNoBubbles) {
// If there are no bubbles the bar is invisible, nothing to do here.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 23e009b..1a4b982 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -242,6 +242,8 @@
bubbleStashedHandleViewController?.setTranslationYForSwipe(translationY)
}
+ override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
+
private fun getStashTranslation(): Float {
return (bubbleBarViewController.bubbleBarCollapsedHeight - stashedHeight) / 2f
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index 92abebe..7d2d36d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -63,10 +63,10 @@
val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
allAppsButton.setIconDrawable(drawable)
- allAppsButton.setPadding(/* left= */ padding)
+ allAppsButton.setPadding(padding)
allAppsButton.setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
- // TODO(jagrutdesai) : add click listeners in future cl
+ // TODO(b/356465292) : add click listeners in future cl
addView(allAppsButton)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
new file mode 100644
index 0000000..26e71f7
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.customization
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import androidx.core.view.setPadding
+import com.android.launcher3.R
+import com.android.launcher3.Utilities.dpToPx
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.views.ActivityContext
+import com.android.launcher3.views.IconButtonView
+
+/** Taskbar divider view container for customizable taskbar. */
+class TaskbarDividerContainer
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : LinearLayout(context, attrs), TaskbarContainer {
+
+ private val taskbarDivider: IconButtonView =
+ LayoutInflater.from(context).inflate(R.layout.taskbar_divider, this, false)
+ as IconButtonView
+ private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+
+ override val spaceNeeded: Int
+ get() {
+ return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+ }
+
+ init {
+ setUpIcon()
+ }
+
+ @SuppressLint("UseCompatLoadingForDrawables")
+ fun setUpIcon() {
+ val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
+ val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+
+ taskbarDivider.setIconDrawable(drawable)
+ taskbarDivider.setPadding(padding)
+
+ // TODO(b/356465292):: add click listeners in future cl
+ addView(taskbarDivider)
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index dea5c1b..bb33c18 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -45,6 +45,7 @@
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
+import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT;
import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP;
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
@@ -75,6 +76,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -215,7 +217,8 @@
import java.util.function.Predicate;
import java.util.stream.Stream;
-public class QuickstepLauncher extends Launcher implements RecentsViewContainer {
+public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
+ SystemShortcut.BubbleActivityStarter {
private static final boolean TRACE_LAYOUTS =
SystemProperties.getBoolean("persist.debug.trace_layouts", false);
private static final String TRACE_RELAYOUT_CLASS =
@@ -466,6 +469,9 @@
if (Flags.enablePrivateSpace()) {
shortcuts.add(UNINSTALL_APP);
}
+ if (com.android.wm.shell.Flags.enableBubbleAnything()) {
+ shortcuts.add(BUBBLE_SHORTCUT);
+ }
return shortcuts.stream();
}
@@ -1382,10 +1388,11 @@
*/
public void launchSplitTasks(
@NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
- // Top/left and bottom/right tasks respectively.
- Task task1 = groupTask.task1;
+ // SplitBounds can be null if coming from Taskbar launch.
+ final boolean firstTaskIsLeftTopTask = isFirstTaskLeftTopTask(groupTask);
// task2 should never be null when calling this method. Allow a crash to catch invalid calls
- Task task2 = groupTask.task2;
+ Task task1 = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
+ Task task2 = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
mSplitSelectStateController.launchExistingSplitPair(
null /* launchingTaskView */,
task1.key.id,
@@ -1399,12 +1406,23 @@
remoteTransition);
}
+ private static boolean isFirstTaskLeftTopTask(@NonNull GroupTask groupTask) {
+ return groupTask.mSplitBounds == null
+ || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
+ }
+
/**
* Launches two apps as an app pair.
*/
public void launchAppPair(AppPairIcon appPairIcon) {
+ // Potentially show the Taskbar education once the app pair launch finishes
mSplitSelectStateController.getAppPairsController().launchAppPair(appPairIcon,
- CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE);
+ CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE,
+ (success) -> {
+ if (success && mTaskbarUIController != null) {
+ mTaskbarUIController.showEduOnAppLaunch();
+ }
+ });
}
public boolean canStartHomeSafely() {
@@ -1436,6 +1454,18 @@
return true;
}
+ @Override
+ public void showShortcutBubble(ShortcutInfo info) {
+ if (info == null) return;
+ SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info);
+ }
+
+ @Override
+ public void showAppBubble(Intent intent) {
+ if (intent == null || intent.getPackage() == null) return;
+ SystemUiProxy.INSTANCE.get(this).showAppBubble(intent);
+ }
+
private static final class LauncherTaskViewController extends
TaskViewTouchController<QuickstepLauncher> {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index d98e608..cb2c324 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -58,8 +58,6 @@
/* If {@code false}, this controller should not handle the input {@link MotionEvent}.*/
private boolean mCanIntercept;
- private boolean mIsTrackpadReverseScroll;
-
public StatusBarTouchController(Launcher l) {
mLauncher = l;
mSystemUiProxy = SystemUiProxy.INSTANCE.get(mLauncher);
@@ -95,8 +93,6 @@
}
mDownEvents.clear();
mDownEvents.put(pid, new PointF(ev.getX(), ev.getY()));
- mIsTrackpadReverseScroll = !mLauncher.isNaturalScrollingEnabled()
- && isTrackpadScroll(ev);
} else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
// Check!! should only set it only when threshold is not entered.
mDownEvents.put(pid, new PointF(ev.getX(idx), ev.getY(idx)));
@@ -107,9 +103,6 @@
if (action == ACTION_MOVE && mDownEvents.contains(pid)) {
float dy = ev.getY(idx) - mDownEvents.get(pid).y;
float dx = ev.getX(idx) - mDownEvents.get(pid).x;
- if (mIsTrackpadReverseScroll) {
- dy = -dy;
- }
// Currently input dispatcher will not do touch transfer if there are more than
// one touch pointer. Hence, even if slope passed, only set the slippery flag
// when there is single touch event. (context: InputDispatcher.cpp line 1445)
@@ -134,7 +127,6 @@
mLauncher.getStatsLogManager().logger()
.log(LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN);
setWindowSlippery(false);
- mIsTrackpadReverseScroll = false;
return true;
}
return true;
@@ -161,9 +153,9 @@
}
private boolean canInterceptTouch(MotionEvent ev) {
- if (!mLauncher.isInState(LauncherState.NORMAL) ||
- AbstractFloatingView.getTopOpenViewWithType(mLauncher,
- AbstractFloatingView.TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW) != null) {
+ if (isTrackpadScroll(ev) || !mLauncher.isInState(LauncherState.NORMAL)
+ || AbstractFloatingView.getTopOpenViewWithType(mLauncher,
+ AbstractFloatingView.TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW) != null) {
return false;
} else {
// For NORMAL state, only listen if the event originated above the navbar height
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 3c7f335..eafc5b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -22,9 +22,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
+import android.graphics.Rect;
import android.os.VibrationEffect;
import android.view.MotionEvent;
-import android.view.View;
import android.view.animation.Interpolator;
import com.android.app.animation.Interpolators;
@@ -67,7 +67,7 @@
protected final CONTAINER mContainer;
private final SingleAxisSwipeDetector mDetector;
private final RecentsView mRecentsView;
- private final int[] mTempCords = new int[2];
+ private final Rect mTempRect = new Rect();
private final boolean mIsRtl;
private AnimatorPlaybackController mCurrentAnimation;
@@ -252,10 +252,8 @@
mTaskBeingDragged, maxDuration, currentInterpolator);
// Since the thumbnail is what is filling the screen, based the end displacement on it.
- View thumbnailView = mTaskBeingDragged.getFirstSnapshotView();
- mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView);
- dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords);
- mEndDisplacement = secondaryLayerDimension - mTempCords[1];
+ mTaskBeingDragged.getThumbnailBounds(mTempRect, /*relativeToDragLayer=*/true);
+ mEndDisplacement = secondaryLayerDimension - mTempRect.bottom;
}
mEndDisplacement *= verticalFactor;
mCurrentAnimation = pa.createPlaybackController();
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index d7ed305..6109fd8 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -105,6 +105,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
@@ -140,6 +141,7 @@
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.contextualeducation.GestureType;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -989,7 +991,6 @@
dp = dp.copy(mContext);
}
dp.updateInsets(targets.homeContentInsets);
- dp.updateIsSeascape(mContext);
initTransitionEndpoints(dp);
orientationState.setMultiWindowMode(dp.isMultiWindowMode);
}
@@ -1409,6 +1410,8 @@
if (mRecentsAnimationController != null) {
mRecentsAnimationController.detachNavigationBarFromApp(true);
}
+ ContextualEduStatsManager.INSTANCE.get(mContext).updateEduStats(
+ mGestureState.isTrackpadGesture(), GestureType.HOME);
} else if (endTarget == RECENTS) {
if (mRecentsView != null) {
int nearestPage = mRecentsView.getDestinationPage();
@@ -1433,6 +1436,8 @@
if (!mGestureState.isHandlingAtomicEvent() || isScrolling) {
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
}
+ ContextualEduStatsManager.INSTANCE.get(mContext).updateEduStats(
+ mGestureState.isTrackpadGesture(), GestureType.OVERVIEW);
}
} else if (endTarget == LAST_TASK && mRecentsView != null
&& mRecentsView.getNextPage() != mRecentsView.getRunningTaskIndex()) {
@@ -2100,7 +2105,6 @@
// If there are no targets, then we don't need to capture anything
mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
} else {
- boolean finishTransitionPosted = false;
// If we already have cached screenshot(s) from running tasks, skip update
boolean shouldUpdate = false;
int[] runningTaskIds = mGestureState.getRunningTaskIds(mIsSwipeForSplit);
@@ -2124,45 +2128,32 @@
}
MAIN_EXECUTOR.execute(() -> {
- if (!updateThumbnail(false /* refreshView */)) {
- setScreenshotCapturedState();
- }
+ updateThumbnail();
+ setScreenshotCapturedState();
});
});
return;
}
- finishTransitionPosted = updateThumbnail(false /* refreshView */);
+ updateThumbnail();
}
- if (!finishTransitionPosted) {
- setScreenshotCapturedState();
- }
+ setScreenshotCapturedState();
}
}
// Returns whether finish transition was posted.
- private boolean updateThumbnail(boolean refreshView) {
+ private void updateThumbnail() {
if (mGestureState.getEndTarget() == HOME
|| mGestureState.getEndTarget() == NEW_TASK
|| mGestureState.getEndTarget() == ALL_APPS
|| mRecentsView == null) {
// Capture the screenshot before finishing the transition to home or quickswitching to
// ensure it's taken in the correct orientation, but no need to update the thumbnail.
- return false;
+ return;
}
- boolean finishTransitionPosted = false;
- TaskView updatedTaskView = mRecentsView.updateThumbnail(mTaskSnapshotCache, refreshView);
- if (updatedTaskView != null && refreshView && !mCanceled) {
- // Defer finishing the animation until the next launcher frame with the
- // new thumbnail
- finishTransitionPosted = ViewUtils.postFrameDrawn(updatedTaskView,
- () -> mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED),
- this::isCanceled);
- }
-
- return finishTransitionPosted;
+ mRecentsView.updateThumbnail(mTaskSnapshotCache);
}
private void setScreenshotCapturedState() {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 00cd60b..293944d 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -31,7 +31,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.graphics.Color;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
@@ -133,7 +132,7 @@
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
TaskbarUIController controller = getTaskbarController();
boolean isEventOverBubbleBarStashHandle =
- controller != null && controller.isEventOverBubbleBarStashHandle(ev);
+ controller != null && controller.isEventOverBubbleBarViews(ev);
return deviceState.isInDeferredGestureRegion(ev) || deviceState.isImeRenderingNavButtons()
|| isTrackpadMultiFingerSwipe(ev) || isEventOverBubbleBarStashHandle;
}
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index 358f644..fbc0d14 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -34,7 +34,7 @@
abstractFloatingViewHelper: AbstractFloatingViewHelper
) :
SystemShortcut<RecentsViewContainer>(
- R.drawable.ic_caption_desktop_button_foreground,
+ R.drawable.ic_desktop,
R.string.recent_task_option_desktop,
container,
taskContainer.itemInfo,
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index da7a98f..32e2389 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -128,15 +128,11 @@
mController::finishAnimationToApp);
} else {
RemoteAnimationTarget[] nonAppTargets;
- if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- nonAppTargets = mSystemUiProxy.onGoingToRecentsLegacy(appTargets);
- } else {
- final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
- final ArrayList<RemoteAnimationTarget> nonApps = new ArrayList<>();
- classifyTargets(appTargets, apps, nonApps);
- appTargets = apps.toArray(new RemoteAnimationTarget[apps.size()]);
- nonAppTargets = nonApps.toArray(new RemoteAnimationTarget[nonApps.size()]);
- }
+ final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
+ final ArrayList<RemoteAnimationTarget> nonApps = new ArrayList<>();
+ classifyTargets(appTargets, apps, nonApps);
+ appTargets = apps.toArray(new RemoteAnimationTarget[apps.size()]);
+ nonAppTargets = nonApps.toArray(new RemoteAnimationTarget[nonApps.size()]);
if (nonAppTargets == null) {
nonAppTargets = new RemoteAnimationTarget[0];
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 3511701..ead5b7b 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -23,7 +23,6 @@
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
-import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -48,7 +47,6 @@
import android.view.IRecentsAnimationRunner;
import android.view.IRemoteAnimationRunner;
import android.view.MotionEvent;
-import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.IOnBackInvokedCallback;
@@ -94,6 +92,7 @@
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.shared.IShellTransitions;
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.splitscreen.ISplitScreen;
@@ -240,6 +239,17 @@
}
@Override
+ public void updateContextualEduStats(boolean isTrackpadGesture, String gestureType) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.updateContextualEduStats(isTrackpadGesture, gestureType);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call updateContextualEduStats");
+ }
+ }
+ }
+
+ @Override
public void setHomeRotationEnabled(boolean enabled) {
if (mSystemUiProxy != null) {
try {
@@ -894,6 +904,36 @@
}
}
+ /**
+ * Tells SysUI to show a shortcut bubble.
+ *
+ * @param info the shortcut info used to create or identify the bubble.
+ */
+ public void showShortcutBubble(ShortcutInfo info) {
+ try {
+ if (mBubbles != null) {
+ mBubbles.showShortcutBubble(info);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call show bubble for shortcut");
+ }
+ }
+
+ /**
+ * Tells SysUI to show a bubble of an app.
+ *
+ * @param intent the intent used to create the bubble.
+ */
+ public void showAppBubble(Intent intent) {
+ try {
+ if (mBubbles != null) {
+ mBubbles.showAppBubble(intent);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call show bubble for app");
+ }
+ }
+
//
// Splitscreen
//
@@ -1000,77 +1040,6 @@
}
}
- /**
- * Start multiple tasks in split-screen simultaneously.
- */
- public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2,
- Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
- splitPosition, snapPosition, adapter, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startTasksWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
- public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1,
- Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, userId1,
- options1, taskId, options2, splitPosition, snapPosition, adapter,
- instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startIntentAndTaskWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
- public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1,
- int taskId, Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1,
- taskId, options2, splitPosition, snapPosition, adapter, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startShortcutAndTaskWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
- /**
- * 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, int userId1,
- @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1,
- PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2,
- @Nullable Bundle options2, @StagePosition int sidePosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, userId1,
- shortcutInfo1, options1, pendingIntent2, userId2, shortcutInfo2, options2,
- sidePosition, snapPosition, adapter, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startIntentsWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
public void startShortcut(String packageName, String shortcutId, int position,
Bundle options, UserHandle user, InstanceId instanceId) {
if (mSplitScreen != null) {
@@ -1105,36 +1074,6 @@
}
}
- /**
- * Call this when going to recents so that shell can set-up and provide appropriate leashes
- * for animation (eg. DividerBar).
- *
- * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
- */
- @Nullable
- public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
- if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS && mSplitScreen != null) {
- try {
- return mSplitScreen.onGoingToRecentsLegacy(apps);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onGoingToRecentsLegacy");
- }
- }
- return null;
- }
-
- @Nullable
- public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
- if (mSplitScreen != null) {
- try {
- return mSplitScreen.onStartingSplitLegacy(apps);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onStartingSplitLegacy");
- }
- }
- return null;
- }
-
//
// One handed
//
@@ -1444,7 +1383,7 @@
private boolean shouldEnableRunningTasksForDesktopMode() {
return DesktopModeStatus.canEnterDesktopMode(mContext)
- && enableDesktopWindowingTaskbarRunningApps();
+ && DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(mContext);
}
private boolean handleMessageAsync(Message msg) {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 723aa03..ab80a8c 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
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.NavigationMode.NO_BUTTON;
@@ -44,6 +45,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.SystemUiFlagUtils;
@@ -264,12 +266,7 @@
}
}
- RemoteAnimationTarget[] nonAppTargets = ENABLE_SHELL_TRANSITIONS
- ? null : getSystemUiProxy().onStartingSplitLegacy(
- appearedTaskTargets);
- if (nonAppTargets == null) {
- nonAppTargets = new RemoteAnimationTarget[0];
- }
+ RemoteAnimationTarget[] nonAppTargets = new RemoteAnimationTarget[0];
if ((containerInterface.isInLiveTileMode()
|| mLastGestureState.getEndTarget() == RECENTS
|| isNonRecentsStartedTasksAppeared(appearedTaskTargets))
@@ -339,6 +336,28 @@
options.setTransientLaunch();
}
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
+
+ // Notify taskbar that we should skip reacting to launcher visibility change to
+ // avoid a jumping taskbar.
+ TaskbarUIController taskbarUIController = containerInterface.getTaskbarController();
+ if (enableScalingRevealHomeAnimation() && taskbarUIController != null) {
+ taskbarUIController.setSkipLauncherVisibilityChange(true);
+
+ mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
+ @Override
+ public void onRecentsAnimationCanceled(
+ @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ taskbarUIController.setSkipLauncherVisibilityChange(false);
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(
+ @NonNull RecentsAnimationController controller) {
+ taskbarUIController.setSkipLauncherVisibilityChange(false);
+ }
+ });
+ }
+
mRecentsAnimationStartPending = getSystemUiProxy()
.startRecentsActivity(intent, options, mCallbacks);
if (enableHandleDelayedGestureCallbacks()) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index bd44283..1a09691 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -232,9 +232,13 @@
TaskViewSimulator::setTaskRectTranslation, taskRectTranslationPrimary,
taskRectTranslationSecondary);
- // Fade in the task during the initial 20% of the animation
- out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1,
- clampToProgress(LINEAR, 0, 0.2f));
+ if (v instanceof DesktopTaskView) {
+ targetHandle.getTransformParams().setTargetAlpha(1f);
+ } else {
+ // Fade in the task during the initial 20% of the animation
+ out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0,
+ 1, clampToProgress(LINEAR, 0, 0.2f));
+ }
}
}
@@ -558,7 +562,7 @@
/**
* Start recents to desktop animation
*/
- public static void composeRecentsDesktopLaunchAnimator(
+ public static AnimatorSet composeRecentsDesktopLaunchAnimator(
@NonNull DesktopTaskView launchingTaskView,
@NonNull StateManager stateManager, @Nullable DepthController depthController,
@NonNull TransitionInfo transitionInfo,
@@ -588,7 +592,7 @@
true /* launcherClosing */, stateManager, launchingTaskView.getRecentsView(),
depthController);
- animatorSet.start();
+ return animatorSet;
}
public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index 6ed05c8..3cf0542 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -28,7 +28,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -48,7 +47,6 @@
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -63,10 +61,6 @@
public class TopTaskTracker extends ISplitScreenListener.Stub
implements TaskStackChangeListener, SafeCloseable {
- private static final String TAG = "TopTaskTracker";
-
- private static final boolean DEBUG = true;
-
public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
new MainThreadInitializedObject<>(TopTaskTracker::new);
@@ -98,19 +92,10 @@
@Override
public void onTaskRemoved(int taskId) {
mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
- if (DEBUG) {
- Log.i(TAG, "onTaskRemoved: taskId=" + taskId);
- }
}
@Override
public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
- if (!mOrderedTaskList.isEmpty()
- && mOrderedTaskList.getFirst().taskId != taskInfo.taskId
- && DEBUG) {
- Log.i(TAG, "onTaskMovedToFront: (moved taskInfo to front) taskId=" + taskInfo.taskId
- + ", baseIntent=" + taskInfo.baseIntent);
- }
mOrderedTaskList.removeIf(rto -> rto.taskId == taskInfo.taskId);
mOrderedTaskList.addFirst(taskInfo);
@@ -121,11 +106,6 @@
final RunningTaskInfo topTaskOnHomeDisplay = mOrderedTaskList.stream()
.filter(rto -> rto.displayId == DEFAULT_DISPLAY).findFirst().orElse(null);
if (topTaskOnHomeDisplay != null) {
- if (DEBUG) {
- Log.i(TAG, "onTaskMovedToFront: (removing top task on home display) taskId="
- + topTaskOnHomeDisplay.taskId
- + ", baseIntent=" + topTaskOnHomeDisplay.baseIntent);
- }
mOrderedTaskList.removeIf(rto -> rto.taskId == topTaskOnHomeDisplay.taskId);
mOrderedTaskList.addFirst(topTaskOnHomeDisplay);
}
@@ -139,10 +119,6 @@
if (info.taskId != taskInfo.taskId
&& info.taskId != mMainStagePosition.taskId
&& info.taskId != mSideStagePosition.taskId) {
- if (DEBUG) {
- Log.i(TAG, "onTaskMovedToFront: (removing task list overflow) taskId="
- + taskInfo.taskId + ", baseIntent=" + taskInfo.baseIntent);
- }
itr.remove();
return;
}
@@ -152,9 +128,6 @@
@Override
public void onStagePositionChanged(@StageType int stage, @StagePosition int position) {
- if (DEBUG) {
- Log.i(TAG, "onStagePositionChanged: stage=" + stage + ", position=" + position);
- }
if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
mMainStagePosition.stagePosition = position;
} else {
@@ -164,10 +137,6 @@
@Override
public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
- if (DEBUG) {
- Log.i(TAG, "onTaskStageChanged: taskId=" + taskId
- + ", stage=" + stage + ", visible=" + visible);
- }
// If a task is not visible anymore or has been moved to undefined, stop tracking it.
if (!visible || stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) {
if (mMainStagePosition.taskId == taskId) {
@@ -187,18 +156,11 @@
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
- if (DEBUG) {
- Log.i(TAG, "onActivityPinned: packageName=" + packageName
- + ", userId=" + userId + ", stackId=" + stackId);
- }
mPinnedTaskId = taskId;
}
@Override
public void onActivityUnpinned() {
- if (DEBUG) {
- Log.i(TAG, "onActivityUnpinned");
- }
mPinnedTaskId = INVALID_TASK_ID;
}
@@ -250,21 +212,6 @@
return new CachedTaskInfo(tasks);
}
- public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + "TopTaskTracker:");
-
- writer.println(prefix + "\tmOrderedTaskList=[");
- for (RunningTaskInfo taskInfo : mOrderedTaskList) {
- writer.println(prefix + "\t\t(taskId=" + taskInfo.taskId
- + "; baseIntent=" + taskInfo.baseIntent
- + "; isRunning=" + taskInfo.isRunning + ")");
- }
- writer.println(prefix + "\t]");
- writer.println(prefix + "\tmMainStagePosition=" + mMainStagePosition);
- writer.println(prefix + "\tmSideStagePosition=" + mSideStagePosition);
- writer.println(prefix + "\tmPinnedTaskId=" + mPinnedTaskId);
- }
-
/**
* Class to provide information about a task which can be safely cached and do not change
* during the lifecycle of the task.
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index a499482..88ab528 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1610,7 +1610,6 @@
pw.println("\tmConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
RecentsModel.INSTANCE.get(this).dump("", pw);
- TopTaskTracker.INSTANCE.get(this).dump("", pw);
if (mTaskAnimationManager != null) {
mTaskAnimationManager.dump("", pw);
}
diff --git a/quickstep/src/com/android/quickstep/contextualeducation/SystemContextualEduStatsManager.java b/quickstep/src/com/android/quickstep/contextualeducation/SystemContextualEduStatsManager.java
new file mode 100644
index 0000000..d470b88
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/contextualeducation/SystemContextualEduStatsManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.contextualeducation;
+
+import android.content.Context;
+
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
+import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.contextualeducation.GestureType;
+
+/**
+ * A class to update contextual education data via {@link SystemUiProxy}
+ */
+public class SystemContextualEduStatsManager extends ContextualEduStatsManager {
+ private Context mContext;
+
+ public SystemContextualEduStatsManager(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void updateEduStats(boolean isTrackpadGesture, GestureType gestureType) {
+ SystemUiProxy.INSTANCE.get(mContext).updateContextualEduStats(isTrackpadGesture,
+ gestureType.name());
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 95295b0..9a99d4a 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -321,8 +321,9 @@
if (controllers == null) {
return false;
}
- if (controllers.bubbleStashController.isStashed()) {
- return controllers.bubbleStashedHandleViewController.containsX((int) x);
+ if (controllers.bubbleStashController.isStashed()
+ && controllers.bubbleStashedHandleViewController.isPresent()) {
+ return controllers.bubbleStashedHandleViewController.get().containsX((int) x);
} else {
Rect bubbleBarBounds = controllers.bubbleBarViewController.getBubbleBarBounds();
return x >= bubbleBarBounds.left && x <= bubbleBarBounds.right;
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index f89888a..54653fa 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -782,7 +782,6 @@
(RelativeLayout.LayoutParams) mFakeHotseatView.getLayoutParams();
if (!mTutorialFragment.isLargeScreen()) {
DeviceProfile dp = mTutorialFragment.getDeviceProfile();
- dp.updateIsSeascape(mContext);
hotseatLayoutParams.addRule(dp.isLandscape
? (dp.isSeascape()
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
index d5aaed5..4f7a541 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -46,5 +46,5 @@
* Override [ThumbnailData] with a map of taskId to [ThumbnailData]. The override only applies
* if the tasks are already visible, and will be invalidated when tasks become invisible.
*/
- fun setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>)
+ fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>)
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 0714170..6f9d157 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -17,115 +17,135 @@
package com.android.quickstep.recents.data
import android.graphics.drawable.Drawable
+import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.task.thumbnail.data.TaskIconDataSource
import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
import com.android.quickstep.util.GroupTask
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.ThumbnailData
import kotlin.coroutines.resume
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
@OptIn(ExperimentalCoroutinesApi::class)
class TasksRepository(
private val recentsModel: RecentTasksDataSource,
private val taskThumbnailDataSource: TaskThumbnailDataSource,
private val taskIconDataSource: TaskIconDataSource,
+ recentsCoroutineScope: CoroutineScope,
+ private val dispatcherProvider: DispatcherProvider,
) : RecentTasksRepository {
private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
- private val _taskData =
- groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
private val visibleTaskIds = MutableStateFlow(emptySet<Int>())
private val thumbnailOverride = MutableStateFlow(mapOf<Int, ThumbnailData>())
- private val taskData: Flow<List<Task>> =
- combine(_taskData, getThumbnailQueryResults(), getIconQueryResults(), thumbnailOverride) {
- tasks,
- thumbnailQueryResults,
- iconQueryResults,
- thumbnailOverride ->
- tasks.forEach { task ->
- // Add retrieved thumbnails + remove unnecessary thumbnails (e.g. invisible)
- task.thumbnail =
- thumbnailOverride[task.key.id] ?: thumbnailQueryResults[task.key.id]
-
- // TODO(b/352331675) don't load icons for DesktopTaskView
- // Add retrieved icons + remove unnecessary icons
- task.icon = iconQueryResults[task.key.id]?.icon
- task.titleDescription = iconQueryResults[task.key.id]?.contentDescription
- task.title = iconQueryResults[task.key.id]?.title
- }
- tasks
+ private val taskData =
+ groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
+ private val visibleTasks =
+ combine(taskData, visibleTaskIds) { tasks, visibleIds ->
+ tasks.filter { it.key.id in visibleIds }
}
+ private val iconQueryResults: Flow<Map<Int, TaskIconQueryResponse?>> =
+ visibleTasks
+ .map { visibleTasksList -> visibleTasksList.map(::getIconDataRequest) }
+ .flatMapLatest { iconRequestFlows: List<IconDataRequest> ->
+ if (iconRequestFlows.isEmpty()) {
+ flowOf(emptyMap())
+ } else {
+ combine(iconRequestFlows) { it.toMap() }
+ }
+ }
+ .distinctUntilChanged()
+
+ private val thumbnailQueryResults: Flow<Map<Int, ThumbnailData?>> =
+ visibleTasks
+ .map { visibleTasksList -> visibleTasksList.map(::getThumbnailDataRequest) }
+ .flatMapLatest { thumbnailRequestFlows: List<ThumbnailDataRequest> ->
+ if (thumbnailRequestFlows.isEmpty()) {
+ flowOf(emptyMap())
+ } else {
+ combine(thumbnailRequestFlows) { it.toMap() }
+ }
+ }
+ .distinctUntilChanged()
+
+ private val augmentedTaskData: Flow<List<Task>> =
+ combine(taskData, thumbnailQueryResults, iconQueryResults, thumbnailOverride) {
+ tasks,
+ thumbnailQueryResults,
+ iconQueryResults,
+ thumbnailOverride ->
+ tasks.onEach { task ->
+ // Add retrieved thumbnails + remove unnecessary thumbnails (e.g. invisible)
+ task.thumbnail =
+ thumbnailOverride[task.key.id] ?: thumbnailQueryResults[task.key.id]
+
+ // TODO(b/352331675) don't load icons for DesktopTaskView
+ // Add retrieved icons + remove unnecessary icons
+ val iconQueryResult = iconQueryResults[task.key.id]
+ task.icon = iconQueryResult?.icon
+ task.titleDescription = iconQueryResult?.contentDescription
+ task.title = iconQueryResult?.title
+ }
+ }
+ .flowOn(dispatcherProvider.io)
+ .shareIn(recentsCoroutineScope, SharingStarted.WhileSubscribed(), replay = 1)
+
override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
if (forceRefresh) {
recentsModel.getTasks { groupedTaskData.value = it }
}
- return taskData
+ return augmentedTaskData
}
override fun getTaskDataById(taskId: Int): Flow<Task?> =
- taskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+ augmentedTaskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
override fun getThumbnailById(taskId: Int): Flow<ThumbnailData?> =
getTaskDataById(taskId).map { it?.thumbnail }.distinctUntilChangedBy { it?.snapshotId }
override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
this.visibleTaskIds.value = visibleTaskIdList.toSet()
- setThumbnailOverride(thumbnailOverride.value)
+ addOrUpdateThumbnailOverride(emptyMap())
}
- override fun setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
+ override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
this.thumbnailOverride.value =
- thumbnailOverride.filterKeys(this.visibleTaskIds.value::contains).toMap()
+ this.thumbnailOverride.value
+ .toMutableMap()
+ .apply { putAll(thumbnailOverride) }
+ .filterKeys(this.visibleTaskIds.value::contains)
}
/** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
- private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest =
- flow {
- emit(task.key.id to task.thumbnail)
- val thumbnailDataResult: ThumbnailData? =
- suspendCancellableCoroutine { continuation ->
- val cancellableTask =
- taskThumbnailDataSource.getThumbnailInBackground(task) {
- continuation.resume(it)
- }
- continuation.invokeOnCancellation { cancellableTask?.cancel() }
- }
- emit(task.key.id to thumbnailDataResult)
+ private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest = flow {
+ emit(task.key.id to task.thumbnail)
+ val thumbnailDataResult: ThumbnailData? =
+ withContext(dispatcherProvider.main) {
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskThumbnailDataSource.getThumbnailInBackground(task) {
+ continuation.resume(it)
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
}
- .distinctUntilChanged()
-
- /**
- * This is a Flow that makes a query for thumbnail data to the [taskThumbnailDataSource] for
- * each visible task. It then collects the responses and returns them in a Map as soon as they
- * are available.
- */
- private fun getThumbnailQueryResults(): Flow<Map<Int, ThumbnailData?>> {
- val visibleTasks =
- combine(_taskData, visibleTaskIds) { tasks, visibleIds ->
- tasks.filter { it.key.id in visibleIds }
- }
- val visibleThumbnailDataRequests: Flow<List<ThumbnailDataRequest>> =
- visibleTasks.map { visibleTasksList -> visibleTasksList.map(::getThumbnailDataRequest) }
- return visibleThumbnailDataRequests.flatMapLatest {
- thumbnailRequestFlows: List<ThumbnailDataRequest> ->
- if (thumbnailRequestFlows.isEmpty()) {
- flowOf(emptyMap())
- } else {
- combine(thumbnailRequestFlows) { it.toMap() }
- }
- }
+ emit(task.key.id to thumbnailDataResult)
}
/** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
@@ -133,43 +153,29 @@
flow {
emit(task.key.id to task.getTaskIconQueryResponse())
val iconDataResponse: TaskIconQueryResponse? =
- suspendCancellableCoroutine { continuation ->
- val cancellableTask =
- taskIconDataSource.getIconInBackground(task) {
- icon,
- contentDescription,
- title ->
- icon.constantState?.let {
- continuation.resume(
- TaskIconQueryResponse(
- it.newDrawable().mutate(),
- contentDescription,
- title
+ withContext(dispatcherProvider.main) {
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskIconDataSource.getIconInBackground(task) {
+ icon,
+ contentDescription,
+ title ->
+ icon.constantState?.let {
+ continuation.resume(
+ TaskIconQueryResponse(
+ it.newDrawable().mutate(),
+ contentDescription,
+ title
+ )
)
- )
+ }
}
- }
- continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
}
emit(task.key.id to iconDataResponse)
}
.distinctUntilChanged()
-
- private fun getIconQueryResults(): Flow<Map<Int, TaskIconQueryResponse?>> {
- val visibleTasks =
- combine(_taskData, visibleTaskIds) { tasks, visibleIds ->
- tasks.filter { it.key.id in visibleIds }
- }
- val visibleIconDataRequests: Flow<List<IconDataRequest>> =
- visibleTasks.map { visibleTasksList -> visibleTasksList.map(::getIconDataRequest) }
- return visibleIconDataRequests.flatMapLatest { iconRequestFlows: List<IconDataRequest> ->
- if (iconRequestFlows.isEmpty()) {
- flowOf(emptyMap())
- } else {
- combine(iconRequestFlows) { it.toMap() }
- }
- }
- }
}
data class TaskIconQueryResponse(
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index eba7688..d8156b1 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.util.Log
import android.view.View
+import com.android.launcher3.util.coroutines.ProductionDispatchers
import com.android.quickstep.RecentsModel
import com.android.quickstep.recents.data.RecentTasksRepository
import com.android.quickstep.recents.data.TasksRepository
@@ -36,6 +37,10 @@
import com.android.quickstep.task.viewmodel.TaskViewModel
import com.android.quickstep.views.TaskViewType
import com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
internal typealias RecentsScopeId = String
@@ -53,11 +58,20 @@
private fun startDefaultScope(appContext: Context) {
createScope(DEFAULT_SCOPE_ID).apply {
set(RecentsViewData::class.java.simpleName, RecentsViewData())
+ val recentsCoroutineScope =
+ CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("RecentsView"))
+ set(CoroutineScope::class.java.simpleName, recentsCoroutineScope)
// Create RecentsTaskRepository singleton
val recentTasksRepository: RecentTasksRepository =
with(RecentsModel.INSTANCE.get(appContext)) {
- TasksRepository(this, thumbnailCache, iconCache)
+ TasksRepository(
+ this,
+ thumbnailCache,
+ iconCache,
+ recentsCoroutineScope,
+ ProductionDispatchers
+ )
}
set(RecentTasksRepository::class.java.simpleName, recentTasksRepository)
}
@@ -137,7 +151,13 @@
when (modelClass) {
RecentTasksRepository::class.java -> {
with(RecentsModel.INSTANCE.get(appContext)) {
- TasksRepository(this, thumbnailCache, iconCache)
+ TasksRepository(
+ this,
+ thumbnailCache,
+ iconCache,
+ get(),
+ ProductionDispatchers
+ )
}
}
RecentsViewData::class.java -> RecentsViewData()
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
index 7205fc8..b1f46a3 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
@@ -58,15 +58,15 @@
recentsViewData.thumbnailSplashProgress.value = taskThumbnailSplashAlpha
}
- fun setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
- recentsTasksRepository.setThumbnailOverride(thumbnailOverride)
+ fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
+ recentsTasksRepository.addOrUpdateThumbnailOverride(thumbnailOverride)
}
suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>) {
combine(
updatedThumbnails.map {
recentsTasksRepository.getThumbnailById(it.key).filter { thumbnailData ->
- thumbnailData == it.value
+ thumbnailData?.snapshotId == it.value.snapshotId
}
}
) {}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 1a20439..ac4032c 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -74,6 +74,7 @@
import java.util.Arrays;
import java.util.List;
+import java.util.function.Consumer;
/**
* Controller class that handles app pair interactions: saving, modifying, deleting, etc.
@@ -232,8 +233,11 @@
*
* @param cuj Should be an integer from {@link Cuj} or -1 if no CUJ needs to be logged for jank
* monitoring
+ * @param callback Called after the app pair launch finishes animating, or null if no method is
+ * to be called
*/
- public void launchAppPair(AppPairIcon appPairIcon, int cuj) {
+ public void launchAppPair(AppPairIcon appPairIcon, int cuj,
+ @Nullable Consumer<Boolean> callback) {
WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp();
WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
@@ -273,12 +277,19 @@
mSplitSelectStateController.setLaunchingIconView(appPairIcon);
mSplitSelectStateController.launchSplitTasks(
- AppPairsController.convertRankToSnapPosition(app1.rank));
+ AppPairsController.convertRankToSnapPosition(app1.rank), callback);
}
);
}
/**
+ * Launches an app pair but does not specify a callback
+ */
+ public void launchAppPair(AppPairIcon appPairIcon, int cuj) {
+ launchAppPair(appPairIcon, cuj, null);
+ }
+
+ /**
* Returns an AppInfo associated with the app for the given ComponentKey, or null if no such
* package exists in the AllAppsStore.
*/
diff --git a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
index 0ce54ad..2e3dee6 100644
--- a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
+++ b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
@@ -81,7 +81,7 @@
try {
mActivityTaskManager.requestAssistDataForTask(
new AssistDataReceiver(callback, this), taskId, mPackageName,
- mAttributionTag);
+ mAttributionTag, false /* fetchStructure */);
} catch (RemoteException e) {
Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index d913b91..2ff8e45 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,7 +16,6 @@
package com.android.quickstep.util;
-import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_LEFT_TOP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTED_SECOND_APP;
@@ -60,8 +59,6 @@
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.RemoteTransition;
@@ -94,13 +91,11 @@
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SplitSelectionListener;
import com.android.quickstep.SystemUiProxy;
-import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.views.FloatingTaskView;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.SplitInstructionsView;
-import com.android.systemui.animation.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -276,17 +271,15 @@
// Loop through tasks in reverse, since they are ordered with recent tasks last
for (int j = taskGroups.size() - 1; j >= 0; j--) {
GroupTask groupTask = taskGroups.get(j);
- Task task1 = groupTask.task1;
- // Don't add duplicate Tasks
- if (isInstanceOfComponent(task1, key)
- && !Arrays.asList(lastActiveTasks).contains(task1)) {
- lastActiveTask = task1;
- break;
+ // Account for desktop cases where there can be N tasks in the group
+ for (Task task : groupTask.getTasks()) {
+ if (isInstanceOfComponent(task, key)
+ && !Arrays.asList(lastActiveTasks).contains(task)) {
+ lastActiveTask = task;
+ break;
+ }
}
- Task task2 = groupTask.task2;
- if (isInstanceOfComponent(task2, key)
- && !Arrays.asList(lastActiveTasks).contains(task2)) {
- lastActiveTask = task2;
+ if (lastActiveTask != null) {
break;
}
}
@@ -460,77 +453,41 @@
Bundle optionsBundle = options1.toBundle();
Bundle extrasBundle = new Bundle(1);
extrasBundle.putParcelable(KEY_EXTRA_WIDGET_INTENT, widgetIntent);
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
- secondTaskId, callback, "LaunchSplitPair");
- switch (launchData.getSplitLaunchType()) {
- case SPLIT_TASK_TASK ->
- mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
- null /* options2 */, initialStagePosition, snapPosition,
- remoteTransition, shellInstanceId);
+ final RemoteTransition remoteTransition = getRemoteTransition(firstTaskId,
+ secondTaskId, callback, "LaunchSplitPair");
+ switch (launchData.getSplitLaunchType()) {
+ case SPLIT_TASK_TASK ->
+ mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
+ null /* options2 */, initialStagePosition, snapPosition,
+ remoteTransition, shellInstanceId);
- case SPLIT_TASK_PENDINGINTENT ->
- mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
- firstTaskId, extrasBundle, initialStagePosition, snapPosition,
- remoteTransition, shellInstanceId);
+ case SPLIT_TASK_PENDINGINTENT ->
+ mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
+ firstTaskId, extrasBundle, initialStagePosition, snapPosition,
+ remoteTransition, shellInstanceId);
- case SPLIT_TASK_SHORTCUT ->
- mSystemUiProxy.startShortcutAndTask(secondShortcut, optionsBundle,
- firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
- remoteTransition, shellInstanceId);
+ case SPLIT_TASK_SHORTCUT ->
+ mSystemUiProxy.startShortcutAndTask(secondShortcut, optionsBundle,
+ firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
+ remoteTransition, shellInstanceId);
- case SPLIT_PENDINGINTENT_TASK ->
- mSystemUiProxy.startIntentAndTask(firstPI, firstUserId, optionsBundle,
- secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
- remoteTransition, shellInstanceId);
+ case SPLIT_PENDINGINTENT_TASK ->
+ mSystemUiProxy.startIntentAndTask(firstPI, firstUserId, optionsBundle,
+ secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
+ remoteTransition, shellInstanceId);
- case SPLIT_PENDINGINTENT_PENDINGINTENT ->
- mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
- optionsBundle, secondPI, secondUserId, secondShortcut, extrasBundle,
- initialStagePosition, snapPosition, remoteTransition,
- shellInstanceId);
+ case SPLIT_PENDINGINTENT_PENDINGINTENT ->
+ mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
+ optionsBundle, secondPI, secondUserId, secondShortcut, extrasBundle,
+ initialStagePosition, snapPosition, remoteTransition,
+ shellInstanceId);
- case SPLIT_SHORTCUT_TASK ->
- mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
- secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
- remoteTransition, shellInstanceId);
- }
- } else {
- final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId, secondTaskId,
- callback);
- switch (launchData.getSplitLaunchType()) {
- case SPLIT_TASK_TASK ->
- mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
- secondTaskId, null /* options2 */, initialStagePosition,
- snapPosition, adapter, shellInstanceId);
-
- case SPLIT_TASK_PENDINGINTENT ->
- mSystemUiProxy.startIntentAndTaskWithLegacyTransition(secondPI,
- secondUserId, optionsBundle, firstTaskId, null /*options2*/,
- initialStagePosition, snapPosition, adapter, shellInstanceId);
-
- case SPLIT_TASK_SHORTCUT ->
- mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(secondShortcut,
- optionsBundle, firstTaskId, null /*options2*/, initialStagePosition,
- snapPosition, adapter, shellInstanceId);
-
- case SPLIT_PENDINGINTENT_TASK ->
- mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI, firstUserId,
- optionsBundle, secondTaskId, null /*options2*/,
- initialStagePosition, snapPosition, adapter, shellInstanceId);
-
- case SPLIT_PENDINGINTENT_PENDINGINTENT ->
- mSystemUiProxy.startIntentsWithLegacyTransition(firstPI, firstUserId,
- firstShortcut, optionsBundle, secondPI, secondUserId,
- secondShortcut, null /*options2*/, initialStagePosition,
- snapPosition, adapter, shellInstanceId);
-
- case SPLIT_SHORTCUT_TASK ->
- mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(firstShortcut,
- optionsBundle, secondTaskId, null /*options2*/,
- initialStagePosition, snapPosition, adapter, shellInstanceId);
- }
+ case SPLIT_SHORTCUT_TASK ->
+ mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
+ secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
+ remoteTransition, shellInstanceId);
}
+
}
/**
@@ -576,20 +533,13 @@
}
Bundle optionsBundle = options1.toBundle();
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- final RemoteTransition transition = remoteTransition == null
- ? getShellRemoteTransition(
- firstTaskId, secondTaskId, callback, "LaunchExistingPair")
- : remoteTransition;
- mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
- stagePosition, snapPosition, transition, null /*shellInstanceId*/);
- } else {
- final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
- secondTaskId, callback);
- mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle, secondTaskId,
- null /* options2 */, stagePosition, snapPosition, adapter,
- null /*shellInstanceId*/);
- }
+ final RemoteTransition transition = remoteTransition == null
+ ? getRemoteTransition(
+ firstTaskId, secondTaskId, callback, "LaunchExistingPair")
+ : remoteTransition;
+ mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
+ stagePosition, snapPosition, transition, null /*shellInstanceId*/);
+
}
/**
@@ -615,34 +565,16 @@
ActivityThread.currentActivityThread().getApplicationThread(),
"LaunchAppFullscreen");
InstanceId instanceId = mSessionInstanceIds.first;
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- switch (launchData.getSplitLaunchType()) {
- case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasks(firstTaskId,
- optionsBundle, secondTaskId, null /* options2 */, initialStagePosition,
- SNAP_TO_50_50, remoteTransition, instanceId);
- case SPLIT_SINGLE_INTENT_FULLSCREEN -> mSystemUiProxy.startIntentAndTask(firstPI,
- firstUserId, optionsBundle, secondTaskId, null /*options2*/,
- initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
- case SPLIT_SINGLE_SHORTCUT_FULLSCREEN -> mSystemUiProxy.startShortcutAndTask(
- initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
- initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
- }
- } else {
- final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
- secondTaskId, callback);
- switch (launchData.getSplitLaunchType()) {
- case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasksWithLegacyTransition(
- firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
- initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
- case SPLIT_SINGLE_INTENT_FULLSCREEN ->
- mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI, firstUserId,
- optionsBundle, secondTaskId, null /*options2*/,
- initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
- case SPLIT_SINGLE_SHORTCUT_FULLSCREEN ->
- mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(
- initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
- initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
- }
+ switch (launchData.getSplitLaunchType()) {
+ case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasks(firstTaskId,
+ optionsBundle, secondTaskId, null /* options2 */, initialStagePosition,
+ SNAP_TO_50_50, remoteTransition, instanceId);
+ case SPLIT_SINGLE_INTENT_FULLSCREEN -> mSystemUiProxy.startIntentAndTask(firstPI,
+ firstUserId, optionsBundle, secondTaskId, null /*options2*/,
+ initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
+ case SPLIT_SINGLE_SHORTCUT_FULLSCREEN -> mSystemUiProxy.startShortcutAndTask(
+ initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
+ initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
}
}
@@ -660,7 +592,7 @@
mSplitFromDesktopController = controller;
}
- private RemoteTransition getShellRemoteTransition(int firstTaskId, int secondTaskId,
+ private RemoteTransition getRemoteTransition(int firstTaskId, int secondTaskId,
@Nullable Consumer<Boolean> callback, String transitionName) {
final RemoteSplitLaunchTransitionRunner animationRunner =
new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
@@ -668,14 +600,6 @@
ActivityThread.currentActivityThread().getApplicationThread(), transitionName);
}
- private RemoteAnimationAdapter getLegacyRemoteAdapter(int firstTaskId, int secondTaskId,
- @Nullable Consumer<Boolean> callback) {
- final RemoteSplitLaunchAnimationRunner animationRunner =
- new RemoteSplitLaunchAnimationRunner(firstTaskId, secondTaskId, callback);
- return new RemoteAnimationAdapter(animationRunner, 300, 150,
- ActivityThread.currentActivityThread().getApplicationThread());
- }
-
/**
* Will initialize {@link #mSessionInstanceIds} if null and log the first split event from
* {@link #mSplitSelectDataHolder}
@@ -807,55 +731,6 @@
}
/**
- * LEGACY
- * Remote animation runner for animation to launch an app.
- */
- private class RemoteSplitLaunchAnimationRunner extends RemoteAnimationRunnerCompat {
-
- private final int mInitialTaskId;
- private final int mSecondTaskId;
- private final Consumer<Boolean> mSuccessCallback;
-
- RemoteSplitLaunchAnimationRunner(int initialTaskId, int secondTaskId,
- @Nullable Consumer<Boolean> successCallback) {
- mInitialTaskId = initialTaskId;
- mSecondTaskId = secondTaskId;
- mSuccessCallback = successCallback;
- }
-
- @Override
- public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
- Runnable finishedCallback) {
- postAsyncCallback(mHandler,
- () -> mSplitAnimationController
- .playSplitLaunchAnimation(mLaunchingTaskView,
- mLaunchingIconView, mInitialTaskId, mSecondTaskId, apps, wallpapers,
- nonApps, mStateManager, mDepthController, null /* info */, null /* t */,
- () -> {
- finishedCallback.run();
- if (mSuccessCallback != null) {
- mSuccessCallback.accept(true);
- }
- resetState();
- },
- QuickStepContract.getWindowCornerRadius(mContainer.asContext())));
- }
-
- @Override
- public void onAnimationCancelled() {
- postAsyncCallback(mHandler, () -> {
- if (mSuccessCallback != null) {
- // Launching legacy tasks while recents animation is running will always cause
- // onAnimationCancelled to be called (should be fixed w/ shell transitions?)
- mSuccessCallback.accept(mRecentsAnimationRunning);
- }
- resetState();
- });
- }
- }
-
- /**
* To be called whenever we exit split selection state. If
* {@link FeatureFlags#enableSplitContextually()} is set, this should be the
* central way split is getting reset, which should then go through the callbacks to reset
@@ -961,7 +836,7 @@
private final int mSplitPlaceholderSize;
private final int mSplitPlaceholderInset;
private ActivityManager.RunningTaskInfo mTaskInfo;
- private ISplitSelectListener mSplitSelectListener;
+ private DesktopSplitSelectListenerImpl mSplitSelectListener;
private Drawable mAppIcon;
public SplitFromDesktopController(QuickstepLauncher launcher,
@@ -972,21 +847,14 @@
R.dimen.split_placeholder_size);
mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize(
R.dimen.split_placeholder_inset);
- mSplitSelectListener = new ISplitSelectListener.Stub() {
- @Override
- public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
- int splitPosition, Rect taskBounds) {
- MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo, splitPosition,
- taskBounds));
- return true;
- }
- };
+ mSplitSelectListener = new DesktopSplitSelectListenerImpl(this);
SystemUiProxy.INSTANCE.get(mLauncher).registerSplitSelectListener(mSplitSelectListener);
}
void onDestroy() {
SystemUiProxy.INSTANCE.get(mLauncher).unregisterSplitSelectListener(
mSplitSelectListener);
+ mSplitSelectListener.release();
mSplitSelectListener = null;
}
@@ -1079,4 +947,35 @@
}
}
}
+
+ /**
+ * Wrapper for the ISplitSelectListener stub to prevent lingering references to the launcher
+ * activity via the controller.
+ */
+ private static class DesktopSplitSelectListenerImpl extends ISplitSelectListener.Stub {
+
+ private SplitFromDesktopController mController;
+
+ DesktopSplitSelectListenerImpl(@NonNull SplitFromDesktopController controller) {
+ mController = controller;
+ }
+
+ /**
+ * Clears any references to the controller.
+ */
+ void release() {
+ mController = null;
+ }
+
+ @Override
+ public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
+ int splitPosition, Rect taskBounds) {
+ MAIN_EXECUTOR.execute(() -> {
+ if (mController != null) {
+ mController.enterSplitSelect(taskInfo, splitPosition, taskBounds);
+ }
+ });
+ return true;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index d9b7d20..e5c54bb 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -171,7 +171,6 @@
mTaskRect.set(mFullTaskSize);
mOrientationState.getOrientationHandler()
.setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
- mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
} else if (mIsDesktopTask) {
// For desktop, tasks can take up only part of the screen size.
// Full task size represents the whole screen size, but scaled down to fit in recents.
@@ -185,10 +184,19 @@
mTaskRect.scale(scale);
// Ensure the task rect is inside the full task rect
mTaskRect.offset(mFullTaskSize.left, mFullTaskSize.top);
+
+ Rect taskDimension = new Rect(0, 0, (int) fullscreenTaskDimension.x,
+ (int) fullscreenTaskDimension.y);
+ mTmpCropRect.set(mThumbnailPosition);
+ if (mTmpCropRect.setIntersect(taskDimension, mThumbnailPosition)) {
+ mTmpCropRect.offset(-mThumbnailPosition.left, -mThumbnailPosition.top);
+ } else {
+ mTmpCropRect.setEmpty();
+ }
} else {
mTaskRect.set(mFullTaskSize);
- mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
}
+ mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
}
/**
@@ -486,10 +494,12 @@
recentsViewPrimaryTranslation.value);
applyWindowToHomeRotation(mMatrix);
- // Crop rect is the inverse of thumbnail matrix
- mTempRectF.set(0, 0, taskWidth, taskHeight);
- mInversePositionMatrix.mapRect(mTempRectF);
- mTempRectF.roundOut(mTmpCropRect);
+ if (!mIsDesktopTask) {
+ // Crop rect is the inverse of thumbnail matrix
+ mTempRectF.set(0, 0, taskWidth, taskHeight);
+ mInversePositionMatrix.mapRect(mTempRectF);
+ mTempRectF.roundOut(mTmpCropRect);
+ }
params.setProgress(1f - fullScreenProgress);
params.applySurfaceParams(surfaceTransaction == null
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 9ce2277..8e48f22 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -19,7 +19,6 @@
import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
-import android.graphics.drawable.LayerDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.util.AttributeSet
@@ -27,9 +26,12 @@
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.core.content.res.ResourcesCompat
import androidx.core.view.updateLayoutParams
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.R
+import com.android.launcher3.testing.TestLogging
+import com.android.launcher3.testing.shared.TestProtocol
import com.android.launcher3.util.RunnableList
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.launcher3.util.TransformingTouchDelegate
@@ -84,9 +86,15 @@
}
iconView =
getOrInflateIconView(R.id.icon).apply {
- val iconBackground = resources.getDrawable(R.drawable.bg_circle, context.theme)
- val icon = resources.getDrawable(R.drawable.ic_desktop, context.theme)
- setIcon(this, LayerDrawable(arrayOf(iconBackground, icon)))
+ setIcon(
+ this,
+ ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.ic_desktop_with_bg,
+ context.theme
+ )
+ )
+ setText(resources.getText(R.string.recent_task_desktop))
}
childCountAtInflation = childCount
}
@@ -213,7 +221,15 @@
}
override fun needsUpdate(dataChange: Int, flag: Int) =
- if (flag == FLAG_UPDATE_THUMBNAIL) super.needsUpdate(dataChange, flag) else false
+ if (flag == FLAG_UPDATE_CORNER_RADIUS) false else super.needsUpdate(dataChange, flag)
+
+ override fun onIconLoaded(taskContainer: TaskContainer) {
+ // Update contentDescription of snapshotView only, individual task icon is unused.
+ taskContainer.snapshotView.contentDescription = taskContainer.task.titleDescription
+ }
+
+ // Ignoring [onIconUnloaded] as all tasks shares the same Desktop icon
+ override fun onIconUnloaded(taskContainer: TaskContainer) {}
// thumbnailView is laid out differently and is handled in onMeasure
override fun updateThumbnailSize() {}
@@ -226,22 +242,33 @@
}
}
- override fun launchTaskAnimated(): RunnableList? {
+ private fun launchTaskWithDesktopController(animated: Boolean): RunnableList? {
val recentsView = recentsView ?: return null
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN,
+ "launchDesktopFromRecents",
+ taskIds.contentToString()
+ )
val endCallback = RunnableList()
val desktopController = recentsView.desktopRecentsController
checkNotNull(desktopController) { "recentsController is null" }
- desktopController.launchDesktopFromRecents(this) { endCallback.executeAllAndDestroy() }
- Log.d(TAG, "launchTaskAnimated - launchDesktopFromRecents: ${taskIds.contentToString()}")
+ desktopController.launchDesktopFromRecents(this, animated) {
+ endCallback.executeAllAndDestroy()
+ }
+ Log.d(
+ TAG,
+ "launchTaskAnimated - launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated"
+ )
// Callbacks get run from recentsView for case when recents animation already running
recentsView.addSideTaskLaunchCallback(endCallback)
return endCallback
}
+ override fun launchTaskAnimated() = launchTaskWithDesktopController(animated = true)
+
override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
- launchTasks()
- callback(true)
+ launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false)
}
// Desktop tile can't be in split screen
@@ -251,8 +278,7 @@
override fun setOverlayEnabled(overlayEnabled: Boolean) {}
override fun onFullscreenProgressChanged(fullscreenProgress: Float) {
- // Don't show background while we are transitioning to/from fullscreen
- backgroundView.visibility = if (fullscreenProgress > 0) INVISIBLE else VISIBLE
+ backgroundView.alpha = 1 - fullscreenProgress
}
override fun updateCurrentFullscreenParams() {
@@ -266,6 +292,7 @@
private const val TAG = "DesktopTaskView"
private const val DEBUG = false
private const val VIEW_POOL_MAX_SIZE = 10
+
// As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool.
private const val VIEW_POOL_INITIAL_SIZE = 0
private val ORIGIN = Point(0, 0)
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 8b6bc39..53e6e72 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -40,6 +40,7 @@
import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
@@ -57,6 +58,7 @@
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.SystemUiController.UI_STATE_FULLSCREEN_TASK;
+import static com.android.quickstep.BaseContainerInterface.getTaskDimension;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_DOWN;
@@ -90,6 +92,7 @@
import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
@@ -135,6 +138,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.PagedView;
@@ -553,6 +557,7 @@
// Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
private float mGridProgress = 0;
private float mTaskThumbnailSplashAlpha = 0;
+ private boolean mBorderEnabled = false;
private boolean mShowAsGridLastOnLayout = false;
private final IntSet mTopRowIdSet = new IntSet();
private int mClearAllShortTotalWidthTranslation = 0;
@@ -1047,8 +1052,11 @@
@Override
@Nullable
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
+ if (enableRefactorTaskThumbnail()) {
+ mHelper.onTaskThumbnailChanged(taskId, thumbnailData);
+ return null;
+ }
if (mHandleTaskStackChanges) {
- // TODO(b/342560598): Handle onTaskThumbnailChanged for new TTV.
if (!enableRefactorTaskThumbnail()) {
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
@@ -1067,6 +1075,7 @@
@Override
public void onTaskIconChanged(String pkg, UserHandle user) {
+ // TODO(b/342560598): Listen in TaskRepository and reload.
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView tv = requireTaskViewAt(i);
Task task = tv.getFirstTask();
@@ -1082,47 +1091,36 @@
@Override
public void onTaskIconChanged(int taskId) {
+ if (enableRefactorTaskThumbnail()) {
+ return;
+ }
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
taskView.refreshTaskThumbnailSplash();
}
}
- /**
- * Update the thumbnail(s) of the relevant TaskView.
- *
- * @param refreshNow Refresh immediately if it's true.
- */
- @Nullable
- public TaskView updateThumbnail(
- HashMap<Integer, ThumbnailData> thumbnailData, boolean refreshNow) {
- if (enableRefactorTaskThumbnail()) {
- // TODO(b/342560598): Handle updateThumbnail for new TTV.
- return null;
- }
- TaskView updatedTaskView = null;
- for (Map.Entry<Integer, ThumbnailData> entry : thumbnailData.entrySet()) {
- Integer id = entry.getKey();
- ThumbnailData thumbnail = entry.getValue();
- TaskView taskView = getTaskViewByTaskId(id);
- if (taskView == null) {
- continue;
+ /** Updates the thumbnail(s) of the relevant TaskView. */
+ public void updateThumbnail(Map<Integer, ThumbnailData> thumbnailData) {
+ if (!enableRefactorTaskThumbnail()) {
+ for (Map.Entry<Integer, ThumbnailData> entry : thumbnailData.entrySet()) {
+ Integer id = entry.getKey();
+ ThumbnailData thumbnail = entry.getValue();
+ TaskView taskView = getTaskViewByTaskId(id);
+ if (taskView == null) {
+ continue;
+ }
+ // taskView could be a GroupedTaskView, so select the relevant task by ID
+ TaskContainer taskContainer = taskView.getTaskContainerById(id);
+ if (taskContainer == null) {
+ continue;
+ }
+ Task task = taskContainer.getTask();
+ TaskThumbnailViewDeprecated taskThumbnailViewDeprecated =
+ taskContainer.getThumbnailViewDeprecated();
+ taskThumbnailViewDeprecated.setThumbnail(task, thumbnail, /*refreshNow=*/false);
}
- // taskView could be a GroupedTaskView, so select the relevant task by ID
- TaskContainer taskAttributes = taskView.getTaskContainerById(id);
- if (taskAttributes == null) {
- continue;
- }
- Task task = taskAttributes.getTask();
- TaskThumbnailViewDeprecated taskThumbnailViewDeprecated =
- taskAttributes.getThumbnailViewDeprecated();
- taskThumbnailViewDeprecated.setThumbnail(task, thumbnail, refreshNow);
- // thumbnailData can contain 1-2 ids, but they should correspond to the same
- // TaskView, so overwriting is ok
- updatedTaskView = taskView;
}
-
- return updatedTaskView;
}
@Override
@@ -1532,6 +1530,7 @@
* Enable or disable showing border on hover and focus change on task views
*/
public void setTaskBorderEnabled(boolean enabled) {
+ mBorderEnabled = enabled;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
@@ -2051,6 +2050,7 @@
taskView.setFullscreenProgress(mFullscreenProgress);
taskView.setModalness(mTaskModalness);
taskView.setTaskThumbnailSplashAlpha(mTaskThumbnailSplashAlpha);
+ taskView.setBorderEnabled(mBorderEnabled);
}
}
// resetTaskVisuals is called at the end of dismiss animation which could update
@@ -2440,10 +2440,6 @@
List<Task> tasksToUpdate = containers.stream()
.map(TaskContainer::getTask)
.collect(Collectors.toCollection(ArrayList::new));
- if (enableRefactorTaskThumbnail()) {
- visibleTaskIds.addAll(
- tasksToUpdate.stream().map((task) -> task.key.id).toList());
- }
if (mTmpRunningTasks != null) {
for (Task t : mTmpRunningTasks) {
// Skip loading if this is the task that we are animating into
@@ -2451,6 +2447,10 @@
tasksToUpdate.removeIf(task -> task == t);
}
}
+ if (enableRefactorTaskThumbnail()) {
+ visibleTaskIds.addAll(
+ tasksToUpdate.stream().map((task) -> task.key.id).toList());
+ }
if (tasksToUpdate.isEmpty()) {
continue;
}
@@ -2507,6 +2507,11 @@
mModel.preloadCacheIfNeeded();
}
+ if (enableRefactorTaskThumbnail()) {
+ // TODO(b/342560598): Listen in TaskRepository and reload.
+ return;
+ }
+
// Whenever the high res loading state changes, poke each of the visible tasks to see if
// they want to updated their thumbnail state
for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
@@ -4919,6 +4924,9 @@
mSplitHiddenTaskView.updateSnapshotRadius();
});
} else if (isInitiatingSplitFromTaskView) {
+ if (Flags.enableHoverOfChildElementsInTaskview()) {
+ mSplitHiddenTaskView.setBorderEnabled(false);
+ }
// Splitting from Overview for fullscreen task
createTaskDismissAnimation(builder, mSplitHiddenTaskView, true, false, duration,
true /* dismissingForSplitSelection*/);
@@ -5227,23 +5235,37 @@
* to the right.
*/
@SuppressLint("Recycle")
- public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) {
+ public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView taskView) {
AnimatorSet anim = new AnimatorSet();
- int taskIndex = indexOfChild(tv);
+ int taskIndex = indexOfChild(taskView);
int centerTaskIndex = getCurrentPage();
float toScale = getMaxScaleForFullScreen();
boolean showAsGrid = showAsGrid();
- boolean launchingCenterTask = showAsGrid
- ? tv.isFocusedTask() && isTaskViewFullyVisible(tv)
+ boolean zoomInTaskView = showAsGrid
+ ? ((taskView.isFocusedTask() && isTaskViewFullyVisible(taskView))
+ || taskView instanceof DesktopTaskView)
: taskIndex == centerTaskIndex;
- if (launchingCenterTask) {
+ if (zoomInTaskView) {
anim.play(ObjectAnimator.ofFloat(this, RECENTS_SCALE_PROPERTY, toScale));
anim.play(ObjectAnimator.ofFloat(this, FULLSCREEN_PROGRESS, 1));
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
+ taskView.getThumbnailBounds(mTempRect, /*relativeToDragLayer=*/true);
+ getTaskDimension(mContext, mContainer.getDeviceProfile(), mTempPointF);
+ Rect fullscreenBounds = new Rect(0, 0, (int) mTempPointF.x,
+ (int) mTempPointF.y);
+ Utilities.getPivotsForScalingRectToRect(mTempRect, fullscreenBounds,
+ mTempPointF);
+ setPivotX(mTempPointF.x);
+ setPivotY(mTempPointF.y);
+ }
+ });
} else if (!showAsGrid) {
// We are launching an adjacent task, so parallax the center and other adjacent task.
- float displacementX = tv.getWidth() * (toScale - 1f);
+ float displacementX = taskView.getWidth() * (toScale - 1f);
float primaryTranslation = mIsRtl ? -displacementX : displacementX;
anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex),
getPagedOrientationHandler().getPrimaryViewTranslate(), primaryTranslation));
@@ -5271,6 +5293,17 @@
}
}
anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0, 1));
+ if (taskView instanceof DesktopTaskView) {
+ anim.play(ObjectAnimator.ofArgb(mContainer.getScrimView(), VIEW_BACKGROUND_COLOR,
+ Color.TRANSPARENT));
+ }
+ DepthController depthController = getDepthController();
+ if (depthController != null) {
+ float targetDepth = taskView instanceof DesktopTaskView ? 0 : BACKGROUND_APP.getDepth(
+ mContainer);
+ anim.play(ObjectAnimator.ofFloat(depthController.stateDepth, MULTI_PROPERTY_VALUE,
+ targetDepth));
+ }
return anim;
}
@@ -5296,7 +5329,7 @@
}
public PendingAnimation createTaskLaunchAnimation(
- TaskView tv, long duration, Interpolator interpolator) {
+ TaskView taskView, long duration, Interpolator interpolator) {
if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
throw new IllegalStateException("Another pending animation is still running");
}
@@ -5311,13 +5344,13 @@
updateGridProperties();
updateScrollSynchronously();
- int targetSysUiFlags = tv.getTaskContainers().getFirst().getSysUiStatusNavFlags();
+ int targetSysUiFlags = taskView.getTaskContainers().getFirst().getSysUiStatusNavFlags();
final boolean[] passedOverviewThreshold = new boolean[]{false};
- ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
- progressAnim.addUpdateListener(animator -> {
+ AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(taskView);
+ anim.play(new AnimatedFloat(v -> {
// Once we pass a certain threshold, update the sysui flags to match the target
// tasks' flags
- if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+ if (v > UPDATE_SYSUI_FLAGS_THRESHOLD) {
mContainer.getSystemUiController().updateUiState(
UI_STATE_FULLSCREEN_TASK, targetSysUiFlags);
} else {
@@ -5325,8 +5358,7 @@
}
// Passing the threshold from taskview to fullscreen app will vibrate
- final boolean passed = animator.getAnimatedFraction() >=
- SUCCESS_TRANSITION_PROGRESS;
+ final boolean passed = v >= SUCCESS_TRANSITION_PROGRESS;
if (passed != passedOverviewThreshold[0]) {
passedOverviewThreshold[0] = passed;
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
@@ -5336,19 +5368,7 @@
mRecentsAnimationController.setWillFinishToHome(!passed);
}
}
- });
-
- AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv);
-
- DepthController depthController = getDepthController();
- if (depthController != null) {
- ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController.stateDepth,
- MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mContainer));
- anim.play(depthAnimator);
- }
- anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0f, 1f));
-
- anim.play(progressAnim);
+ }).animateToValue(0f, 1f));
anim.setInterpolator(interpolator);
mPendingAnimation = new PendingAnimation(duration);
@@ -5357,9 +5377,18 @@
remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
.addOverviewToAppAnim(mPendingAnimation, interpolator));
mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
+ if (taskView instanceof DesktopTaskView && mRemoteTargetHandles != null) {
+ mPendingAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
+ }
+ });
+ }
mPendingAnimation.addEndListener(isSuccess -> {
if (isSuccess) {
- if (tv instanceof GroupedTaskView && hasAllValidTaskIds(tv.getTaskIds())
+ if (taskView instanceof GroupedTaskView && hasAllValidTaskIds(taskView.getTaskIds())
&& mRemoteTargetHandles != null) {
// TODO(b/194414938): make this part of the animations instead.
TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
@@ -5369,13 +5398,13 @@
dividerAnimator.end();
});
}
- if (tv.isRunningTask()) {
+ if (taskView.isRunningTask()) {
finishRecentsAnimation(false /* toRecents */, null);
onTaskLaunchAnimationEnd(true /* success */);
} else {
- tv.launchTask(this::onTaskLaunchAnimationEnd);
+ taskView.launchTask(this::onTaskLaunchAnimationEnd);
}
- mContainer.getStatsLogManager().logger().withItemInfo(tv.getFirstItemInfo())
+ mContainer.getStatsLogManager().logger().withItemInfo(taskView.getFirstItemInfo())
.log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
} else {
onTaskLaunchAnimationEnd(false);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
index 05c2462..e8c9718 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
@@ -60,9 +60,6 @@
// Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside
// viewAttachedScope.
recentsViewModel.setRunningTaskShowScreenshot(true)
- if (updatedThumbnails != null) {
- recentsViewModel.setThumbnailOverride(updatedThumbnails)
- }
viewAttachedScope.launch {
recentsViewModel.waitForRunningTaskShowScreenshotToUpdate()
if (updatedThumbnails != null) {
@@ -71,4 +68,8 @@
ViewUtils.postFrameDrawn(taskView, onFinishRunnable)
}
}
+
+ fun onTaskThumbnailChanged(taskId: Int, thumbnailData: ThumbnailData) {
+ recentsViewModel.addOrUpdateThumbnailOverride(mapOf(taskId to thumbnailData))
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index e10d38c..158ae33 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -42,7 +42,11 @@
companion object {
const val TAG = "TaskMenuViewWithArrow"
- fun showForTask(taskContainer: TaskContainer, alignedOptionIndex: Int = 0): Boolean {
+ fun showForTask(
+ taskContainer: TaskContainer,
+ alignedOptionIndex: Int = 0,
+ onClosedCallback: Runnable? = null
+ ): Boolean {
val container: RecentsViewContainer =
RecentsViewContainer.containerFromContext(taskContainer.taskView.context)
val taskMenuViewWithArrow =
@@ -52,7 +56,11 @@
false
) as TaskMenuViewWithArrow<*>
- return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignedOptionIndex)
+ return taskMenuViewWithArrow.populateAndShowForTask(
+ taskContainer,
+ alignedOptionIndex,
+ onClosedCallback
+ )
}
}
@@ -98,6 +106,7 @@
private var iconView: IconView? = null
private var scrim: View? = null
private val scrimAlpha = 0.8f
+ private var onClosedCallback: Runnable? = null
override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
@@ -141,7 +150,8 @@
private fun populateAndShowForTask(
taskContainer: TaskContainer,
- alignedOptionIndex: Int
+ alignedOptionIndex: Int,
+ onClosedCallback: Runnable?
): Boolean {
if (isAttachedToWindow) {
return false
@@ -150,6 +160,7 @@
taskView = taskContainer.taskView
this.taskContainer = taskContainer
this.alignedOptionIndex = alignedOptionIndex
+ this.onClosedCallback = onClosedCallback
if (!populateMenu()) return false
addScrim()
show()
@@ -252,6 +263,7 @@
super.closeComplete()
popupContainer.removeView(scrim)
popupContainer.removeView(iconView)
+ onClosedCallback?.run()
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 292595c..176a538 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -48,6 +48,7 @@
import com.android.launcher3.Flags.enableCursorHoverStates
import com.android.launcher3.Flags.enableFocusOutline
import com.android.launcher3.Flags.enableGridOnlyOverview
+import com.android.launcher3.Flags.enableHoverOfChildElementsInTaskview
import com.android.launcher3.Flags.enableOverviewIconMenu
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.R
@@ -413,6 +414,26 @@
focusBorderAnimator?.setBorderVisibility(visible = field && isFocused, animated = true)
}
+ /**
+ * Used to cache the hover border state so we don't repeatedly call the border animator with
+ * every hover event when the user hasn't crossed the threshold of the [thumbnailBounds].
+ */
+ private var hoverBorderVisible = false
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ Log.d(
+ TAG,
+ "${taskIds.contentToString()} - setting border animator visibility to: $field"
+ )
+ hoverBorderAnimator?.setBorderVisibility(visible = field, animated = true)
+ }
+
+ // Used to cache thumbnail bounds to avoid recalculating on every hover move.
+ private var thumbnailBounds = Rect()
+
private var focusTransitionProgress = 1f
set(value) {
field = value
@@ -511,20 +532,28 @@
override fun onHoverEvent(event: MotionEvent): Boolean {
if (borderEnabled) {
when (event.action) {
- MotionEvent.ACTION_HOVER_ENTER ->
- hoverBorderAnimator?.setBorderVisibility(visible = true, animated = true)
- MotionEvent.ACTION_HOVER_EXIT ->
- hoverBorderAnimator?.setBorderVisibility(visible = false, animated = true)
+ MotionEvent.ACTION_HOVER_ENTER -> {
+ hoverBorderVisible =
+ if (enableHoverOfChildElementsInTaskview()) {
+ getThumbnailBounds(thumbnailBounds)
+ event.isWithinThumbnailBounds()
+ } else {
+ true
+ }
+ }
+ MotionEvent.ACTION_HOVER_MOVE ->
+ if (enableHoverOfChildElementsInTaskview())
+ hoverBorderVisible = event.isWithinThumbnailBounds()
+ MotionEvent.ACTION_HOVER_EXIT -> hoverBorderVisible = false
else -> {}
}
}
return super.onHoverEvent(event)
}
- // avoid triggering hover event on child elements which would cause HOVER_EXIT for this
- // task view
- override fun onInterceptHoverEvent(event: MotionEvent) =
- if (enableCursorHoverStates()) true else super.onInterceptHoverEvent(event)
+ override fun onInterceptHoverEvent(event: MotionEvent): Boolean =
+ if (enableHoverOfChildElementsInTaskview()) super.onInterceptHoverEvent(event)
+ else if (enableCursorHoverStates()) true else super.onInterceptHoverEvent(event)
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
val recentsView = recentsView ?: return false
@@ -567,6 +596,9 @@
it.right = width
it.bottom = height
}
+ if (enableHoverOfChildElementsInTaskview()) {
+ getThumbnailBounds(thumbnailBounds)
+ }
}
override fun onRecycle() {
@@ -579,6 +611,7 @@
setOverlayEnabled(false)
onTaskListVisibilityChanged(false)
borderEnabled = false
+ hoverBorderVisible = false
taskViewId = UNBOUND_TASK_VIEW_ID
taskContainers.forEach { it.destroy() }
}
@@ -868,18 +901,11 @@
it.task.icon = icon
it.task.titleDescription = contentDescription
it.task.title = title
- setIcon(it.iconView, icon)
- if (enableOverviewIconMenu()) {
- setText(it.iconView, title)
- }
- it.digitalWellBeingToast?.initialize(it.task)
+ onIconLoaded(it)
}
?.also { request -> pendingIconLoadRequests.add(request) }
} else {
- setIcon(it.iconView, null)
- if (enableOverviewIconMenu()) {
- setText(it.iconView, null)
- }
+ onIconUnloaded(it)
}
}
}
@@ -898,6 +924,21 @@
pendingIconLoadRequests.clear()
}
+ protected open fun onIconLoaded(taskContainer: TaskContainer) {
+ setIcon(taskContainer.iconView, taskContainer.task.icon)
+ if (enableOverviewIconMenu()) {
+ setText(taskContainer.iconView, taskContainer.task.title)
+ }
+ taskContainer.digitalWellBeingToast?.initialize(taskContainer.task)
+ }
+
+ protected open fun onIconUnloaded(taskContainer: TaskContainer) {
+ setIcon(taskContainer.iconView, null)
+ if (enableOverviewIconMenu()) {
+ setText(taskContainer.iconView, null)
+ }
+ }
+
protected fun setIcon(iconView: TaskViewIcon, icon: Drawable?) {
with(iconView) {
if (icon != null) {
@@ -1119,6 +1160,11 @@
isClickableAsLiveTile = true
return runnableList
}
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN,
+ "composeRecentsLaunchAnimator",
+ taskIds.contentToString()
+ )
val runnableList = RunnableList()
with(AnimatorSet()) {
TaskViewUtils.composeRecentsLaunchAnimator(
@@ -1225,10 +1271,17 @@
private fun showTaskMenuWithContainer(menuContainer: TaskContainer): Boolean {
val recentsView = recentsView ?: return false
+ if (enableHoverOfChildElementsInTaskview()) {
+ // Disable hover on all TaskView's whilst menu is showing.
+ recentsView.setTaskBorderEnabled(false)
+ }
return if (enableOverviewIconMenu() && menuContainer.iconView is IconAppChipView) {
menuContainer.iconView.revealAnim(/* isRevealing= */ true)
TaskMenuView.showForTask(menuContainer) {
menuContainer.iconView.revealAnim(/* isRevealing= */ false)
+ if (enableHoverOfChildElementsInTaskview()) {
+ recentsView.setTaskBorderEnabled(true)
+ }
}
} else if (container.deviceProfile.isTablet) {
val alignedOptionIndex =
@@ -1248,9 +1301,17 @@
} else {
0
}
- TaskMenuViewWithArrow.showForTask(menuContainer, alignedOptionIndex)
+ TaskMenuViewWithArrow.showForTask(menuContainer, alignedOptionIndex) {
+ if (enableHoverOfChildElementsInTaskview()) {
+ recentsView.setTaskBorderEnabled(true)
+ }
+ }
} else {
- TaskMenuView.showForTask(menuContainer)
+ TaskMenuView.showForTask(menuContainer) {
+ if (enableHoverOfChildElementsInTaskview()) {
+ recentsView.setTaskBorderEnabled(true)
+ }
+ }
}
}
@@ -1398,7 +1459,6 @@
protected open fun refreshTaskThumbnailSplash() {
if (!enableRefactorTaskThumbnail()) {
- // TODO(b/342560598) handle onTaskIconChanged
taskContainers.forEach { it.thumbnailViewDeprecated.refreshSplashView() }
}
}
@@ -1584,6 +1644,10 @@
override fun close() {}
}
+ private fun MotionEvent.isWithinThumbnailBounds(): Boolean {
+ return thumbnailBounds.contains(x.toInt(), y.toInt())
+ }
+
companion object {
private const val TAG = "TaskView"
const val FLAG_UPDATE_ICON = 1
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
new file mode 100644
index 0000000..3e0d6b5
--- /dev/null
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar.bubbles
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.util.PathParser
+import android.view.LayoutInflater
+import androidx.test.core.app.ApplicationProvider
+import com.android.launcher3.R
+import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.Displays
+import platform.test.screenshot.ViewScreenshotTestRule
+import platform.test.screenshot.getEmulatedDevicePathConfig
+
+/** Screenshot tests for [BubbleView]. */
+@RunWith(ParameterizedAndroidJunit4::class)
+class BubbleViewScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+
+ companion object {
+ @Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() =
+ DeviceEmulationSpec.forDisplays(
+ Displays.Phone,
+ isDarkTheme = false,
+ isLandscape = false
+ )
+ }
+
+ @get:Rule
+ val screenshotRule =
+ ViewScreenshotTestRule(
+ emulationSpec,
+ ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec))
+ )
+
+ @Test
+ fun bubbleView_hasUnseenContent() {
+ screenshotRule.screenshotTest("bubbleView_hasUnseenContent") { activity ->
+ activity.actionBar?.hide()
+ setupBubbleView()
+ }
+ }
+
+ @Test
+ fun bubbleView_seen() {
+ screenshotRule.screenshotTest("bubbleView_seen") { activity ->
+ activity.actionBar?.hide()
+ setupBubbleView().apply { markSeen() }
+ }
+ }
+
+ @Test
+ fun bubbleView_badgeHidden() {
+ screenshotRule.screenshotTest("bubbleView_badgeHidden") { activity ->
+ activity.actionBar?.hide()
+ setupBubbleView().apply { setBadgeScale(0f) }
+ }
+ }
+
+ private fun setupBubbleView(): BubbleView {
+ val inflater = LayoutInflater.from(context)
+
+ val iconSize = 100
+ // BubbleView uses launcher's badge to icon ratio and expects the badge image to already
+ // have the right size
+ val badgeToIconRatio = 0.444f
+ val badgeRadius = iconSize * badgeToIconRatio / 2
+ val icon = createCircleBitmap(radius = iconSize / 2, color = Color.LTGRAY)
+ val badge = createCircleBitmap(radius = badgeRadius.toInt(), color = Color.RED)
+
+ val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+ val bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null) as BubbleView
+ val dotPath =
+ PathParser.createPathFromPathData(
+ context.resources.getString(com.android.internal.R.string.config_icon_mask)
+ )
+ val bubble =
+ BubbleBarBubble(bubbleInfo, bubbleView, badge, icon, Color.BLUE, dotPath, "test app")
+ bubbleView.setBubble(bubble)
+ bubbleView.showDotIfNeeded(1f)
+ return bubbleView
+ }
+
+ private fun createCircleBitmap(radius: Int, color: Int): Bitmap {
+ val bitmap = Bitmap.createBitmap(radius * 2, radius * 2, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bitmap)
+ canvas.drawARGB(0, 0, 0, 0)
+ val paint = Paint()
+ paint.color = color
+ canvas.drawCircle(radius.toFloat(), radius.toFloat(), radius.toFloat(), paint)
+ return bitmap
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt
index e583f63..961d4dc 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarEduTooltipControllerTest.kt
@@ -14,11 +14,18 @@
* limitations under the License.
*/
-package com.android.launcher3.taskbar
+package com.android.launcher3.taskbar.test
+import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.Utilities
+import com.android.launcher3.taskbar.TOOLTIP_STEP_FEATURES
+import com.android.launcher3.taskbar.TOOLTIP_STEP_NONE
+import com.android.launcher3.taskbar.TOOLTIP_STEP_PINNING
+import com.android.launcher3.taskbar.TOOLTIP_STEP_SWIPE
+import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
+import com.android.launcher3.taskbar.TaskbarEduTooltipController
import com.android.launcher3.taskbar.rules.TaskbarModeRule
import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.THREE_BUTTONS
@@ -35,12 +42,14 @@
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(LauncherMultivalentJUnit::class)
@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+@Ignore
class TaskbarEduTooltipControllerTest {
private val context =
@@ -48,25 +57,25 @@
InstrumentationRegistry.getInstrumentation().targetContext
)
- @get:Rule
+ @get:Rule(order = 0)
val tooltipStepPreferenceRule =
TaskbarPreferenceRule(
context,
OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP.prefItem,
)
- @get:Rule
+ @get:Rule(order = 1)
val searchEduPreferenceRule =
TaskbarPreferenceRule(
context,
OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN,
)
- @get:Rule val taskbarPinningPreferenceRule = TaskbarPinningPreferenceRule(context)
+ @get:Rule(order = 2) val taskbarPinningPreferenceRule = TaskbarPinningPreferenceRule(context)
- @get:Rule val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 3) val taskbarModeRule = TaskbarModeRule(context)
- @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+ @get:Rule(order = 4) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
@InjectController lateinit var taskbarEduTooltipController: TaskbarEduTooltipController
@@ -77,6 +86,7 @@
@Before
fun setUp() {
+ Log.e("Taskbar", "TaskbarEduTooltipControllerTest test started")
Utilities.disableRunningInTestHarnessForTests()
}
@@ -85,6 +95,7 @@
if (wasInTestHarness) {
Utilities.enableRunningInTestHarnessForTests()
}
+ Log.e("Taskbar", "TaskbarEduTooltipControllerTest test completed")
}
@Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index e9c0dd6..4da06e1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -35,8 +35,8 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
import com.android.launcher3.taskbar.bubbles.BubbleBarOverflow
import com.android.launcher3.taskbar.bubbles.BubbleBarView
-import com.android.launcher3.taskbar.bubbles.BubbleStashController
import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.common.bubbles.BubbleInfo
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
@@ -78,13 +78,13 @@
val handle = View(context)
val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.animateBubbleInForStashed(bubble)
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
}
// let the animation start and wait for it to complete
@@ -98,7 +98,7 @@
assertThat(bubbleBarView.scaleX).isEqualTo(1)
assertThat(bubbleBarView.scaleY).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
// execute the hide bubble animation
assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -111,7 +111,7 @@
assertThat(handle.alpha).isEqualTo(1)
assertThat(handle.translationY).isEqualTo(0)
assertThat(bubbleBarView.alpha).isEqualTo(0)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
verify(bubbleStashController).stashBubbleBarImmediate()
}
@@ -122,13 +122,13 @@
val handle = View(context)
val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.animateBubbleInForStashed(bubble)
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
}
// let the animation start and wait for it to complete
@@ -142,7 +142,7 @@
assertThat(bubbleBarView.scaleX).isEqualTo(1)
assertThat(bubbleBarView.scaleY).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
verify(bubbleStashController, atLeastOnce()).updateTaskbarTouchRegion()
@@ -155,7 +155,7 @@
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
}
@Test
@@ -165,13 +165,13 @@
val handle = View(context)
val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.animateBubbleInForStashed(bubble)
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
}
// wait for the animation to start
@@ -179,7 +179,7 @@
PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
handleAnimator.assertIsRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -189,7 +189,7 @@
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
// PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
@@ -205,13 +205,13 @@
val handle = View(context)
val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.animateBubbleInForStashed(bubble)
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
}
// let the animation start and wait for it to complete
@@ -230,7 +230,7 @@
animator.onStashStateChangingWhileAnimating()
}
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
// PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
@@ -246,13 +246,13 @@
val handle = View(context)
val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.animateBubbleInForStashed(bubble)
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
}
// wait for the animation to start
@@ -260,16 +260,133 @@
PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
handleAnimator.assertIsRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
assertThat(animatorScheduler.delayedBlock).isNotNull()
handleAnimator.cancel()
handleAnimator.assertIsNotRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(animatorScheduler.delayedBlock).isNull()
}
@Test
+ fun animateBubbleInForStashed_autoExpanding() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble, isExpanding = true)
+ }
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(handle.alpha).isEqualTo(0)
+ assertThat(handle.translationY)
+ .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(1)
+ assertThat(bubbleBarView.scaleY).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(animator.isAnimating).isFalse()
+ assertThat(bubbleBarView.isExpanded).isTrue()
+
+ // verify there is no hide animation
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateBubbleInForStashed_expandedWhileAnimatingIn() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
+ }
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
+
+ handleAnimator.assertIsRunning()
+ assertThat(animator.isAnimating).isTrue()
+ // verify the hide bubble animation is pending
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.expandedWhileAnimating()
+ }
+
+ // let the animation finish
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ assertThat(handle.alpha).isEqualTo(0)
+ assertThat(handle.translationY)
+ .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+ verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(animator.isAnimating).isFalse()
+ }
+
+ @Test
+ fun animateBubbleInForStashed_expandedWhileFullyIn() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble, isExpanding = false)
+ }
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ // wait for the animation to end
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(animator.isAnimating).isTrue()
+ // verify the hide bubble animation is pending
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.expandedWhileAnimating()
+ }
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ assertThat(handle.alpha).isEqualTo(0)
+ assertThat(handle.translationY)
+ .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+ verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(animator.isAnimating).isFalse()
+ }
+
+ @Test
fun animateToInitialState_inApp() {
setUpBubbleBar()
setUpBubbleStashController()
@@ -278,7 +395,7 @@
val handle = View(context)
val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
@@ -293,7 +410,7 @@
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
barAnimator.assertIsNotRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
@@ -304,7 +421,7 @@
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.alpha).isEqualTo(0)
assertThat(handle.translationY).isEqualTo(0)
assertThat(handle.alpha).isEqualTo(1)
@@ -321,7 +438,7 @@
val handle = View(context)
val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+ whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
@@ -336,17 +453,11 @@
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
barAnimator.assertIsNotRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
- assertThat(animatorScheduler.delayedBlock).isNotNull()
- InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
-
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
- assertThat(bubbleBarView.alpha).isEqualTo(1)
- assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
-
+ assertThat(animatorScheduler.delayedBlock).isNull()
verify(bubbleStashController).showBubbleBarImmediate()
}
@@ -370,14 +481,14 @@
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
barAnimator.assertIsNotRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
@@ -385,6 +496,79 @@
}
@Test
+ fun animateToInitialState_expandedWhileAnimatingIn() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
+ }
+
+ val bubbleBarAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(bubbleBarAnimator) { true }
+
+ bubbleBarAnimator.assertIsRunning()
+ assertThat(animator.isAnimating).isTrue()
+ // verify the hide bubble animation is pending
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.expandedWhileAnimating()
+ }
+
+ // let the animation finish
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ assertThat(animator.isAnimating).isFalse()
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateToInitialState_expandedWhileFullyIn() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
+ }
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(animator.isAnimating).isTrue()
+ // verify the hide bubble animation is pending
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.expandedWhileAnimating()
+ }
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ assertThat(animator.isAnimating).isFalse()
+ }
+
+ @Test
fun animateBubbleBarForCollapsed() {
setUpBubbleBar()
setUpBubbleStashController()
@@ -397,12 +581,12 @@
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.animateBubbleBarForCollapsed(bubble)
+ animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
}
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
// verify we started animating
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
// advance the animation handler by the duration of the initial lift
InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -417,13 +601,149 @@
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
// the bubble bar translation y should be back to its initial value
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
verify(bubbleStashController).showBubbleBarImmediate()
}
+ @Test
+ fun animateBubbleBarForCollapsed_autoExpanding() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleBarForCollapsed(bubble, isExpanding = true)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ // verify we started animating
+ assertThat(animator.isAnimating).isTrue()
+
+ // advance the animation handler by the duration of the initial lift
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ // the lift animation is complete; the spring back animation should start now
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ barAnimator.assertIsRunning()
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ // verify there is no hide animation
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ assertThat(animator.isAnimating).isFalse()
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ assertThat(bubbleBarView.isExpanded).isTrue()
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateBubbleBarForCollapsed_expandingWhileAnimatingIn() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ // verify we started animating
+ assertThat(animator.isAnimating).isTrue()
+
+ // advance the animation handler by the duration of the initial lift
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ // the lift animation is complete; the spring back animation should start now
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ barAnimator.assertIsRunning()
+ PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(barAnimator) { true }
+
+ // verify there is a pending hide animation
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ assertThat(animator.isAnimating).isTrue()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.expandedWhileAnimating()
+ }
+
+ // let the animation finish
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ assertThat(animator.isAnimating).isFalse()
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ assertThat(bubbleBarView.isExpanded).isTrue()
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateBubbleBarForCollapsed_expandingWhileFullyIn() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ // verify we started animating
+ assertThat(animator.isAnimating).isTrue()
+
+ // advance the animation handler by the duration of the initial lift
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ // the lift animation is complete; the spring back animation should start now
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ barAnimator.assertIsRunning()
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ // verify there is a pending hide animation
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ assertThat(animator.isAnimating).isTrue()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.expandedWhileAnimating()
+ }
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+
+ assertThat(animator.isAnimating).isFalse()
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ assertThat(bubbleBarView.isExpanded).isTrue()
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
private fun setUpBubbleBar() {
bubbleBarView = BubbleBarView(context)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -451,14 +771,22 @@
private fun setUpBubbleStashController() {
bubbleStashController = mock<BubbleStashController>()
whenever(bubbleStashController.isStashed).thenReturn(true)
- whenever(bubbleStashController.diffBetweenHandleAndBarCenters)
+ whenever(bubbleStashController.getDiffBetweenHandleAndBarCenters())
.thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS)
- whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation)
+ whenever(bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation())
.thenReturn(HANDLE_TRANSLATION)
whenever(bubbleStashController.bubbleBarTranslationYForTaskbar)
.thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
}
+ private fun verifyBubbleBarIsExpandedWithTranslation(ty: Float) {
+ assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(1)
+ assertThat(bubbleBarView.scaleY).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(ty)
+ assertThat(bubbleBarView.isExpanded).isTrue()
+ }
+
private fun <T> PhysicsAnimator<T>.assertIsRunning() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
assertThat(isRunning()).isTrue()
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
index 00ad3b7..0f8a2c3 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
@@ -17,7 +17,7 @@
package com.android.launcher3.taskbar.bubbles.stashing
class ImmediateAction : BubbleStashController.ControllersAfterInitAction {
- override fun runAfterInit(action: () -> Unit) = action.invoke()
+ override fun runAfterInit(action: Runnable) = action.run()
}
class DefaultDimensionsProvider(
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt
index f75e542..f7e4576 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarModeRuleTest.kt
@@ -24,6 +24,7 @@
import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
import com.android.launcher3.util.NavigationMode
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
@@ -31,6 +32,7 @@
import org.junit.runner.RunWith
@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
class TaskbarModeRuleTest {
private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
index a709133..a515405 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
@@ -19,6 +19,7 @@
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
import com.android.launcher3.util.window.WindowManagerProxy
import com.google.android.apps.nexuslauncher.deviceemulator.TestWindowManagerProxy
import com.google.common.truth.Truth.assertThat
@@ -28,6 +29,7 @@
import org.junit.runners.model.Statement
@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
class TaskbarPinningPreferenceRuleTest {
private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
index 22d2079..46817d2 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPreferenceRuleTest.kt
@@ -19,6 +19,7 @@
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.Description
@@ -26,6 +27,7 @@
import org.junit.runners.model.Statement
@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
class TaskbarPreferenceRuleTest {
private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
index 234e499..5d4fdc5 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRuleTest.kt
@@ -34,7 +34,7 @@
import org.junit.runners.model.Statement
@RunWith(LauncherMultivalentJUnit::class)
-@EmulatedDevices(["pixelFoldable2023"])
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
class TaskbarUnitTestRuleTest {
private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt
index ad4b4de..4834d48 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContextTest.kt
@@ -25,6 +25,7 @@
import org.junit.runner.RunWith
@RunWith(LauncherMultivalentJUnit::class)
+@LauncherMultivalentJUnit.EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
class TaskbarWindowSandboxContextTest {
private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
new file mode 100644
index 0000000..1f88743
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.graphics.PointF
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.R
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.shared.system.InputConsumerController
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LauncherSwipeHandlerV2Test {
+
+ @Mock private lateinit var taskAnimationManager: TaskAnimationManager
+
+ private lateinit var gestureState: GestureState
+ @Mock private lateinit var inputConsumerController: InputConsumerController
+
+ @Mock private lateinit var systemUiProxy: SystemUiProxy
+
+ private lateinit var underTest: LauncherSwipeHandlerV2
+
+ @get:Rule val mockitoRule = MockitoJUnit.rule()
+
+ private val launcherModelHelper = LauncherModelHelper()
+ private val sandboxContext = launcherModelHelper.sandboxContext
+
+ private val flingSpeed =
+ -(sandboxContext.resources.getDimension(R.dimen.quickstep_fling_threshold_speed) + 1)
+
+ @Before
+ fun setup() {
+ sandboxContext.putObject(SystemUiProxy.INSTANCE, systemUiProxy)
+ val deviceState = mock(RecentsAnimationDeviceState::class.java)
+ whenever(deviceState.rotationTouchHelper).thenReturn(mock(RotationTouchHelper::class.java))
+ gestureState = spy(GestureState(OverviewComponentObserver(sandboxContext, deviceState), 0))
+
+ underTest =
+ LauncherSwipeHandlerV2(
+ sandboxContext,
+ deviceState,
+ taskAnimationManager,
+ gestureState,
+ 0,
+ false,
+ inputConsumerController
+ )
+ underTest.onGestureStarted(/* isLikelyToStartNewTask= */ false)
+ }
+
+ @Test
+ fun goHomeFromAppByTrackpad_updateEduStats() {
+ gestureState.setTrackpadGestureType(GestureState.TrackpadGestureType.THREE_FINGER)
+ underTest.onGestureEnded(flingSpeed, PointF())
+ verify(systemUiProxy)
+ .updateContextualEduStats(
+ /* isTrackpadGesture= */ eq(true),
+ eq(GestureType.HOME.toString())
+ )
+ }
+
+ @Test
+ fun goHomeFromAppByTouch_updateEduStats() {
+ underTest.onGestureEnded(flingSpeed, PointF())
+ verify(systemUiProxy)
+ .updateContextualEduStats(
+ /* isTrackpadGesture= */ eq(false),
+ eq(GestureType.HOME.toString())
+ )
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
index ea2e484..d2479bc 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -20,8 +20,9 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.ALLOW_ROTATION
import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
-import com.android.launcher3.LauncherPrefs.Companion.backedUpItem
+import com.android.launcher3.SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY
import com.android.launcher3.logging.InstanceId
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_NEW_APPS_TO_HOME_SCREEN_ENABLED
@@ -32,6 +33,10 @@
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED
+import com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY
+import com.google.android.apps.nexuslauncher.PrefKey.KEY_ENABLE_MINUS_ONE
+import com.google.android.apps.nexuslauncher.PrefKey.OVERVIEW_SUGGESTED_ACTIONS
+import com.google.android.apps.nexuslauncher.PrefKey.SMARTSPACE_ON_HOME_SCREEN
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -62,6 +67,7 @@
@Captor private lateinit var mEventCaptor: ArgumentCaptor<StatsLogManager.EventEnum>
private var mDefaultThemedIcons = false
+ private var mDefaultAllowRotation = false
@Before
fun setUp() {
@@ -70,8 +76,11 @@
whenever(mStatsLogManager.logger()).doReturn(mMockLogger)
whenever(mStatsLogManager.logger().withInstanceId(any())).doReturn(mMockLogger)
mDefaultThemedIcons = LauncherPrefs.get(mContext).get(THEMED_ICONS)
+ mDefaultAllowRotation = LauncherPrefs.get(mContext).get(ALLOW_ROTATION)
// To match the default value of THEMED_ICONS
LauncherPrefs.get(mContext).put(THEMED_ICONS, false)
+ // To match the default value of ALLOW_ROTATION
+ LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = false)
mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
}
@@ -79,18 +88,19 @@
@After
fun tearDown() {
LauncherPrefs.get(mContext).put(THEMED_ICONS, mDefaultThemedIcons)
- mSystemUnderTest.close()
+ LauncherPrefs.get(mContext).put(ALLOW_ROTATION, mDefaultAllowRotation)
}
@Test
fun loggingPrefs_correctDefaultValue() {
- assertThat(mSystemUnderTest.loggingPrefs["pref_allowRotation"]!!.defaultValue).isFalse()
- assertThat(mSystemUnderTest.loggingPrefs["pref_add_icon_to_home"]!!.defaultValue).isTrue()
- assertThat(mSystemUnderTest.loggingPrefs["pref_overview_action_suggestions"]!!.defaultValue)
- .isTrue()
- assertThat(mSystemUnderTest.loggingPrefs["pref_smartspace_home_screen"]!!.defaultValue)
- .isTrue()
- assertThat(mSystemUnderTest.loggingPrefs["pref_enable_minus_one"]!!.defaultValue).isTrue()
+ val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
+
+ assertThat(systemUnderTest.loggingPrefs[ALLOW_ROTATION_PREFERENCE_KEY]!!.defaultValue)
+ .isFalse()
+ assertThat(systemUnderTest.loggingPrefs[ADD_ICON_PREFERENCE_KEY]!!.defaultValue).isTrue()
+ assertThat(systemUnderTest.loggingPrefs[OVERVIEW_SUGGESTED_ACTIONS]!!.defaultValue).isTrue()
+ assertThat(systemUnderTest.loggingPrefs[SMARTSPACE_ON_HOME_SCREEN]!!.defaultValue).isTrue()
+ assertThat(systemUnderTest.loggingPrefs[KEY_ENABLE_MINUS_ONE]!!.defaultValue).isTrue()
}
@Test
@@ -101,24 +111,16 @@
val capturedEvents = mEventCaptor.allValues
assertThat(capturedEvents.isNotEmpty()).isTrue()
verifyDefaultEvent(capturedEvents)
- // pref_allowRotation false
assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_ROTATION_DISABLED.id })
.isTrue()
}
@Test
- fun logSnapshot_updateValue() {
- LauncherPrefs.get(mContext)
- .put(
- item =
- backedUpItem(
- sharedPrefKey = "pref_allowRotation",
- defaultValue = false,
- ),
- value = true
- )
+ fun logSnapshot_updateAllowRotation() {
+ LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = true)
- mSystemUnderTest.logSnapshot(mInstanceId)
+ // This a new object so the values of mLoggablePrefs will be different
+ SettingsChangeLogger(mContext, mStatsLogManager).logSnapshot(mInstanceId)
verify(mMockLogger, atLeastOnce()).log(mEventCaptor.capture())
val capturedEvents = mEventCaptor.allValues
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
index e488413..d94a351 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -65,7 +65,7 @@
setThumbnailOverrideInternal(thumbnailOverrideMap)
}
- override fun setThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
+ override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
setThumbnailOverrideInternal(thumbnailOverride)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index aee5d1e..e6534eb 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -20,6 +20,7 @@
import android.content.Intent
import android.graphics.Bitmap
import android.view.Surface
+import com.android.launcher3.util.TestDispatcherProvider
import com.android.quickstep.task.thumbnail.TaskThumbnailViewModelTest
import com.android.quickstep.util.DesktopTask
import com.android.quickstep.util.GroupTask
@@ -27,10 +28,8 @@
import com.android.systemui.shared.recents.model.ThumbnailData
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.flow.toList
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -50,201 +49,232 @@
private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
private val taskIconDataSource = FakeTaskIconDataSource()
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(dispatcher)
private val systemUnderTest =
- TasksRepository(recentsModel, taskThumbnailDataSource, taskIconDataSource)
+ TasksRepository(
+ recentsModel,
+ taskThumbnailDataSource,
+ taskIconDataSource,
+ testScope.backgroundScope,
+ TestDispatcherProvider(dispatcher)
+ )
@Test
- fun getAllTaskDataReturnsFlattenedListOfTasks() = runTest {
- recentsModel.seedTasks(defaultTaskList)
+ fun getAllTaskDataReturnsFlattenedListOfTasks() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
- assertThat(systemUnderTest.getAllTaskData(forceRefresh = true).first()).isEqualTo(tasks)
- }
-
- @Test
- fun getTaskDataByIdReturnsSpecificTask() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2])
- }
-
- @Test
- fun setVisibleTasksPopulatesThumbnails() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- assertThat(systemUnderTest.getTaskDataById(1).drop(1).first()!!.thumbnail!!.thumbnail)
- .isEqualTo(bitmap1)
- assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
- .isEqualTo(bitmap2)
- }
-
- @Test
- fun setVisibleTasksPopulatesIcons() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- systemUnderTest
- .getTaskDataById(1)
- .drop(1)
- .first()!!
- .assertHasIconDataFromSource(taskIconDataSource)
- systemUnderTest.getTaskDataById(2).first()!!.assertHasIconDataFromSource(taskIconDataSource)
- }
-
- @Test
- fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- assertThat(systemUnderTest.getTaskDataById(2).drop(1).first()!!.thumbnail!!.thumbnail)
- .isEqualTo(bitmap2)
-
- // Prevent new loading of Bitmaps
- taskThumbnailDataSource.shouldLoadSynchronously = false
- systemUnderTest.setVisibleTasks(listOf(2, 3))
-
- assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
- .isEqualTo(bitmap2)
- }
-
- @Test
- fun changingVisibleTasksContainsAlreadyPopulatedIcons() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- // .drop(1) to ignore initial null content before from icon was loaded.
- systemUnderTest
- .getTaskDataById(2)
- .drop(1)
- .first()!!
- .assertHasIconDataFromSource(taskIconDataSource)
-
- // Prevent new loading of Drawables
- taskThumbnailDataSource.shouldLoadSynchronously = false
- systemUnderTest.setVisibleTasks(listOf(2, 3))
-
- systemUnderTest.getTaskDataById(2).first()!!.assertHasIconDataFromSource(taskIconDataSource)
- }
-
- @Test
- fun retrievedImagesAreDiscardedWhenTaskBecomesInvisible() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- val task2 = systemUnderTest.getTaskDataById(2).drop(1).first()!!
- assertThat(task2.thumbnail!!.thumbnail).isEqualTo(bitmap2)
- task2.assertHasIconDataFromSource(taskIconDataSource)
-
- // Prevent new loading of Bitmaps
- taskThumbnailDataSource.shouldLoadSynchronously = false
- taskIconDataSource.shouldLoadSynchronously = false
- systemUnderTest.setVisibleTasks(listOf(0, 1))
-
- val task2AfterVisibleTasksChanged = systemUnderTest.getTaskDataById(2).first()!!
- assertThat(task2AfterVisibleTasksChanged.thumbnail).isNull()
- assertThat(task2AfterVisibleTasksChanged.icon).isNull()
- assertThat(task2AfterVisibleTasksChanged.titleDescription).isNull()
- assertThat(task2AfterVisibleTasksChanged.title).isNull()
- }
-
- @Test
- fun retrievedThumbnailsCauseEmissionOnTaskDataFlow() = runTest {
- // Setup fakes
- recentsModel.seedTasks(defaultTaskList)
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- taskThumbnailDataSource.shouldLoadSynchronously = false
-
- // Setup TasksRepository
- systemUnderTest.getAllTaskData(forceRefresh = true)
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- // Assert there is no bitmap in first emission
- val taskFlow = systemUnderTest.getTaskDataById(2)
- val taskFlowValuesList = mutableListOf<Task?>()
- backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
- taskFlow.toList(taskFlowValuesList)
+ assertThat(systemUnderTest.getAllTaskData(forceRefresh = true).first()).isEqualTo(tasks)
}
- assertThat(taskFlowValuesList[0]!!.thumbnail).isNull()
-
- // Simulate bitmap loading after first emission
- taskThumbnailDataSource.taskIdToUpdatingTask.getValue(2).invoke()
-
- // Check for second emission
- assertThat(taskFlowValuesList[1]!!.thumbnail!!.thumbnail).isEqualTo(bitmap2)
- }
@Test
- fun setThumbnailOverrideOverrideThumbnails() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- val thumbnailOverride = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
+ fun getTaskDataByIdReturnsSpecificTask() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
- systemUnderTest.setVisibleTasks(listOf(1))
- systemUnderTest.setThumbnailOverride(mapOf(2 to thumbnailOverride))
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- assertThat(systemUnderTest.getThumbnailById(1).drop(1).first()!!.thumbnail)
- .isEqualTo(bitmap1)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
- }
+ assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2])
+ }
@Test
- fun setThumbnailOverrideClearedWhenTaskBecomeInvisible() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- val thumbnailOverride = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
+ fun setVisibleTasksPopulatesThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
- systemUnderTest.setVisibleTasks(listOf(1, 2))
- systemUnderTest.setThumbnailOverride(mapOf(2 to thumbnailOverride))
- systemUnderTest.setVisibleTasks(listOf(1))
- systemUnderTest.setVisibleTasks(listOf(1, 2))
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- assertThat(systemUnderTest.getThumbnailById(1).drop(1).first()!!.thumbnail)
- .isEqualTo(bitmap1)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
- }
+ assertThat(systemUnderTest.getTaskDataById(1).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap1)
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
@Test
- fun setThumbnailOverrideDoesNotOverrideInvisibleTasks() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val thumbnailOverride = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
+ fun setVisibleTasksPopulatesIcons() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
- systemUnderTest.setVisibleTasks(listOf(1, 2))
- systemUnderTest.setThumbnailOverride(mapOf(2 to thumbnailOverride))
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- assertThat(systemUnderTest.getThumbnailById(1).drop(1).first()!!.thumbnail)
- .isEqualTo(bitmap1)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride.thumbnail)
- }
+ systemUnderTest
+ .getTaskDataById(1)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+ systemUnderTest
+ .getTaskDataById(2)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+ }
+
+ @Test
+ fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+
+ // Prevent new loading of Bitmaps
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(2, 3))
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
+
+ @Test
+ fun changingVisibleTasksContainsAlreadyPopulatedIcons() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ systemUnderTest
+ .getTaskDataById(2)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+
+ // Prevent new loading of Drawables
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(2, 3))
+
+ systemUnderTest
+ .getTaskDataById(2)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+ }
+
+ @Test
+ fun retrievedImagesAreDiscardedWhenTaskBecomesInvisible() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ val task2 = systemUnderTest.getTaskDataById(2).first()!!
+ assertThat(task2.thumbnail!!.thumbnail).isEqualTo(bitmap2)
+ task2.assertHasIconDataFromSource(taskIconDataSource)
+
+ // Prevent new loading of Bitmaps
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ taskIconDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(0, 1))
+
+ val task2AfterVisibleTasksChanged = systemUnderTest.getTaskDataById(2).first()!!
+ assertThat(task2AfterVisibleTasksChanged.thumbnail).isNull()
+ assertThat(task2AfterVisibleTasksChanged.icon).isNull()
+ assertThat(task2AfterVisibleTasksChanged.titleDescription).isNull()
+ assertThat(task2AfterVisibleTasksChanged.title).isNull()
+ }
+
+ @Test
+ fun retrievedThumbnailsCauseEmissionOnTaskDataFlow() =
+ testScope.runTest {
+ // Setup fakes
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+
+ // Setup TasksRepository
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // Assert there is no bitmap in first emission
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail).isNull()
+
+ // Simulate bitmap loading after first emission
+ taskThumbnailDataSource.taskIdToUpdatingTask.getValue(2).invoke()
+
+ // Check for second emission
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
+
+ @Test
+ fun addThumbnailOverrideOverrideThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+ val thumbnailOverride2 = createThumbnailData()
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+ systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
+
+ assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
+ assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
+ .isEqualTo(thumbnailOverride2.thumbnail)
+ }
+
+ @Test
+ fun addThumbnailOverrideMultipleOverrides() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val thumbnailOverride1 = createThumbnailData()
+ val thumbnailOverride2 = createThumbnailData()
+ val thumbnailOverride3 = createThumbnailData()
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+ systemUnderTest.addOrUpdateThumbnailOverride(mapOf(1 to thumbnailOverride1))
+ systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
+ systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride3))
+
+ assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
+ .isEqualTo(thumbnailOverride1.thumbnail)
+ assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
+ .isEqualTo(thumbnailOverride3.thumbnail)
+ }
+
+ @Test
+ fun addThumbnailOverrideClearedWhenTaskBecomeInvisible() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ val thumbnailOverride1 = createThumbnailData()
+ val thumbnailOverride2 = createThumbnailData()
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+ systemUnderTest.addOrUpdateThumbnailOverride(mapOf(1 to thumbnailOverride1))
+ systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
+ // Making task 2 invisible and visible again should clear the override
+ systemUnderTest.setVisibleTasks(listOf(1))
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
+ .isEqualTo(thumbnailOverride1.thumbnail)
+ assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
+ }
+
+ @Test
+ fun addThumbnailOverrideDoesNotOverrideInvisibleTasks() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ val thumbnailOverride = createThumbnailData()
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1))
+ systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride))
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
+ assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
+ }
private fun createTaskWithId(taskId: Int) =
Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000))
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
index 00dbcc1..dc16475 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
@@ -72,9 +72,8 @@
@Test
fun thumbnailOverrideWaitAndReset() = runTest {
- val thumbnailData1 = createThumbnailData()
- val thumbnailData2 = createThumbnailData()
- val thumbnailDataOverride = createThumbnailData()
+ val thumbnailData1 = createThumbnailData().apply { snapshotId = 1 }
+ val thumbnailData2 = createThumbnailData().apply { snapshotId = 2 }
tasksRepository.seedTasks(tasks)
tasksRepository.seedThumbnailData(mapOf(1 to thumbnailData1, 2 to thumbnailData2))
@@ -87,15 +86,16 @@
assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
- val thumbnailUpdate = mapOf(2 to thumbnailDataOverride)
systemUnderTest.setRunningTaskShowScreenshot(true)
- systemUnderTest.setThumbnailOverride(thumbnailUpdate)
+ val thumbnailOverride = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
+ systemUnderTest.addOrUpdateThumbnailOverride(thumbnailOverride)
systemUnderTest.waitForRunningTaskShowScreenshotToUpdate()
- systemUnderTest.waitForThumbnailsToUpdate(thumbnailUpdate)
+ val expectedUpdate = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
+ systemUnderTest.waitForThumbnailsToUpdate(expectedUpdate)
assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
- assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailDataOverride)
+ assertThat(thumbnailDataFlow2.first()?.snapshotId).isEqualTo(3)
systemUnderTest.onReset()
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
index ef3a833..67a0ee4 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
@@ -202,7 +202,7 @@
boolean hoverHandled =
mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
- assertThat(hoverHandled).isFalse();
+ assertThat(hoverHandled).isTrue();
}
@Test
@@ -213,7 +213,7 @@
boolean hoverHandled =
mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
- assertThat(hoverHandled).isFalse();
+ assertThat(hoverHandled).isTrue();
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index 1886ce6..a8f39af 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -31,6 +31,10 @@
static final int STRESS_REPEAT_COUNT = 10;
+ private enum TestCase {
+ TO_HOME, TO_OVERVIEW,
+ }
+
@Override
@Before
public void setUp() throws Exception {
@@ -41,28 +45,55 @@
}
@Test
- @NavigationModeSwitch
+ @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
public void testStressPressHome() {
- for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
- // Destroy Launcher activity.
- closeLauncherActivity();
-
- // The test action.
- mLauncher.goHome();
- }
+ runTest(TestCase.TO_HOME);
}
@Test
- @NavigationModeSwitch
+ @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.ZERO_BUTTON)
+ public void testStressSwipeHome() {
+ runTest(TestCase.TO_HOME);
+ }
+
+ @Test
+ @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
+ public void testStressPressOverview() {
+ runTest(TestCase.TO_OVERVIEW);
+ }
+
+ @Test
+ @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.ZERO_BUTTON)
public void testStressSwipeToOverview() {
+ runTest(TestCase.TO_OVERVIEW);
+ }
+
+ private void runTest(TestCase testCase) {
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
closeLauncherActivity();
// The test action.
- mLauncher.getLaunchedAppState().switchToOverview();
+ switch (testCase) {
+ case TO_OVERVIEW:
+ mLauncher.getLaunchedAppState().switchToOverview();
+ break;
+ case TO_HOME:
+ mLauncher.goHome();
+ break;
+ default:
+ throw new IllegalStateException("Cannot run test case: " + testCase);
+ }
}
- closeLauncherActivity();
- mLauncher.goHome();
+ switch (testCase) {
+ case TO_OVERVIEW:
+ closeLauncherActivity();
+ mLauncher.goHome();
+ break;
+ case TO_HOME:
+ default:
+ // No-Op
+ break;
+ }
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
new file mode 100644
index 0000000..694a382
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import android.platform.test.rule.AllowedDevices
+import android.platform.test.rule.DeviceProduct
+import android.platform.test.rule.IgnoreLimit
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.launcher3.BuildConfig
+import com.android.launcher3.ui.AbstractLauncherUiTest
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+
+/** Test Desktop windowing in Overview. */
+@AllowedDevices(allowed = [DeviceProduct.CF_TABLET, DeviceProduct.TANGORPRO])
+@IgnoreLimit(ignoreLimit = BuildConfig.IS_STUDIO_BUILD)
+class TaplTestsOverviewDesktop : AbstractLauncherUiTest<QuickstepLauncher?>() {
+ @Before
+ fun setup() {
+ val overview = mLauncher.goHome().switchToOverview()
+ if (overview.hasTasks()) {
+ overview.dismissAllTasks()
+ }
+ startTestAppsWithCheck()
+ mLauncher.goHome()
+ }
+
+ @Test
+ @PortraitLandscape
+ fun enterDesktopViaOverviewMenu() {
+ // Move last launched TEST_ACTIVITY_2 into Desktop
+ mLauncher.workspace
+ .switchToOverview()
+ .getTestActivityTask(TEST_ACTIVITY_2)
+ .tapMenu()
+ .tapDesktopMenuItem()
+ assertTestAppLaunched(TEST_ACTIVITY_2)
+
+ // Scroll back to TEST_ACTIVITY_1, then move it into Desktop
+ mLauncher
+ .goHome()
+ .switchToOverview()
+ .apply { flingForward() }
+ .getTestActivityTask(TEST_ACTIVITY_1)
+ .tapMenu()
+ .tapDesktopMenuItem()
+ TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
+
+ // Launch static DesktopTaskView
+ val desktop =
+ mLauncher.goHome().switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open()
+ TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
+
+ // Launch live-tile DesktopTaskView
+ desktop.switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open()
+ TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
+ }
+
+ private fun startTestAppsWithCheck() {
+ TEST_ACTIVITIES.forEach {
+ startTestActivity(it)
+ executeOnLauncher { launcher ->
+ assertWithMessage(
+ "Launcher activity is the top activity; expecting TestActivity$it"
+ )
+ .that(isInLaunchedApp(launcher))
+ .isTrue()
+ }
+ }
+ }
+
+ private fun assertTestAppLaunched(index: Int) {
+ assertWithMessage("TestActivity$index not opened in Desktop")
+ .that(
+ mDevice.wait(
+ Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity$index")),
+ DEFAULT_UI_TIMEOUT
+ )
+ )
+ .isTrue()
+ }
+
+ companion object {
+ const val TEST_ACTIVITY_1 = 2
+ const val TEST_ACTIVITY_2 = 3
+ val TEST_ACTIVITIES = listOf(TEST_ACTIVITY_1, TEST_ACTIVITY_2)
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 1dfab26..cb815fe 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -356,6 +356,7 @@
@Test
@TaskbarModeSwitch
+ @ScreenRecord // b/358607191
public void testQuickSwitchToPreviousAppForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 2d79623..3a83ae3 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -16,7 +16,7 @@
package com.android.quickstep;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
@@ -71,7 +71,7 @@
final ArgumentCaptor<ActivityOptions> optionsCaptor =
ArgumentCaptor.forClass(ActivityOptions.class);
verify(mSystemUiProxy).startRecentsActivity(any(), optionsCaptor.capture(), any());
- assertTrue(optionsCaptor.getValue()
- .isPendingIntentBackgroundActivityLaunchAllowedByPermission());
+ assertEquals(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS,
+ optionsCaptor.getValue().getPendingIntentBackgroundActivityStartMode());
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
index 512557b..dc1da69 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
@@ -88,18 +88,6 @@
}
@Test
- public void showBorderOnHoverEvent() {
- mTaskView.setBorderEnabled(/* enabled= */ true);
- MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
- mTaskView.onHoverEvent(MotionEvent.obtain(event));
- verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
- true);
- mTaskView.onFocusChanged(true, 0, new Rect());
- verify(mFocusAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
- true);
- }
-
- @Test
public void showBorderOnBorderEnabled() {
presetBorderStatus(/* enabled= */ false);
mTaskView.setBorderEnabled(/* enabled= */ true);
diff --git a/res/color-night-v31/material_color_surface_container_lowest.xml b/res/color-night-v31/material_color_surface_container_lowest.xml
new file mode 100644
index 0000000..4396f6d
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_container_lowest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="4" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_lowest.xml b/res/color-v31/material_color_surface_container_lowest.xml
new file mode 100644
index 0000000..f726aea
--- /dev/null
+++ b/res/color-v31/material_color_surface_container_lowest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="100" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable/ic_bubble_button.xml b/res/drawable/ic_bubble_button.xml
new file mode 100644
index 0000000..1ed212e
--- /dev/null
+++ b/res/drawable/ic_bubble_button.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/res/drawable/ic_desktop_with_bg.xml b/res/drawable/ic_desktop_with_bg.xml
new file mode 100644
index 0000000..f54285c
--- /dev/null
+++ b/res/drawable/ic_desktop_with_bg.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="M24,2L24,2A22,22 0,0 1,46 24L46,24A22,22 0,0 1,24 46L24,46A22,22 0,0 1,2 24L2,24A22,22 0,0 1,24 2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M32,30H16V18H32V30ZM32,32C33.1,32 34,31.1 34,30V18C34,16.9 33.1,16 32,16H16C14.9,16 14,16.9 14,18V30C14,31.1 14.9,32 16,32H32ZM30,20H23V22H28V24H30V20ZM18,23H27V28H18V23Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/res/drawable/private_space_install_app_icon.xml b/res/drawable/private_space_install_app_icon.xml
index 12c4a82..cfec2b1 100644
--- a/res/drawable/private_space_install_app_icon.xml
+++ b/res/drawable/private_space_install_app_icon.xml
@@ -23,9 +23,9 @@
android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z" />
<path
android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z"
- android:fillColor="?attr/materialColorSurfaceContainerLowest" />
+ android:fillColor="@color/material_color_surface_container_lowest" />
<path
android:pathData="M29 31h-6v-2h6v-6h2v6h6v2h-6v6h-2v-6Z"
- android:fillColor="?attr/materialColorOnSurface" />
+ android:fillColor="@color/material_color_on_surface" />
</group>
</vector>
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index e68f0f3..6bce220 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -100,6 +100,7 @@
android:gravity="center_vertical"
android:layout_marginStart="@dimen/ps_header_layout_margin"
android:text="@string/ps_container_title"
+ android:maxLines="1"
android:theme="@style/PrivateSpaceHeaderTextStyle"
android:importantForAccessibility="no"/>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index dca7cab..8b4b26a 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vasspeldvoorspelling"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installeer kortpaaie"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Laat \'n program toe om kortpaaie by te voeg sonder gebruikerinmenging."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lees tuis-instellings en -kortpaaie"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 3e0eaf7..03f62bf 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ጫን"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"መተግበሪያውን አይጠቁሙ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"የፒን ግምት"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"አቋራጮችን ይጭናል"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"መተግበሪያው ያለተጠቃሚ ጣልቃ ገብነት አቋራጭ እንዲያክል ያስችለዋል።"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"የመነሻ ቅንብሮች እና አቋራጮችን ያነባል"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 794c249..31ebd34 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"تثبيت"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"عدم اقتراح التطبيق"</string>
<string name="pin_prediction" msgid="4196423321649756498">"تثبيت التطبيق المتوقّع"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"تثبيت اختصارات"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"للسماح لتطبيق ما بإضافة اختصارات بدون تدخل المستخدم."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"الاطلاع على الإعدادات والاختصارات على الشاشة الرئيسية"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 55a80b4..e2f4ecd 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনষ্টল কৰক"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"পৰামৰ্শ নিদিব"</string>
<string name="pin_prediction" msgid="4196423321649756498">"পূৰ্বানুমান কৰা এপ্টো পিন কৰক"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"শ্বৰ্টকাট ইনষ্টল কৰিব পাৰে"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ব্য়ৱহাৰকাৰীৰ হস্তক্ষেপ অবিহনেই কোনো এপক শ্বৰ্টকাটবোৰ যোগ কৰাৰ অনুমতি দিয়ে।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"গৃহ স্ক্ৰীনত ছেটিং আৰু শ্বৰ্টকাটসমূহ পঢ়া"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 7713e89..520295e 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Quraşdırın"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tətbiq təklif olunmasın"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Proqnozlaşdırılan tətbiqi bərkidin"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"qısayolları quraşdır"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Tətbiqə istifadəçi müdaxiləsi olmadan qısayolları əlavə etməyə icazə verir."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Əsas səhifə ayarlarını və qısayollarını oxumaq"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 71bd34c..09ddf76 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečica"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Dozvoljava aplikaciji da dodaje prečice bez intervencije korisnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čitanje podešavanja i prečica na početnom ekranu"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index edb9a35..85792f7 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Стварэнне ярлыкоў"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Дазваляе праграмам дадаваць ярлыкі без умяшання карыстальніка."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"счытваць налады і ярлыкі на галоўным экране"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 3d39828..baf405d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталиране"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Без предлагане на приложение"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Фиксиране на предвиждането"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталиране на преки пътища"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Разрешава на приложението да добавя преки пътища без намеса на потребителя."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"четене на настройките и преките пътища на началния екран"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 09ebf2f..a6bdde1 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
<string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"শর্টকাটগুলি ইনস্টল করে"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"একটি অ্যাপ্লিকেশানকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি যোগ করার অনুমতি দেয়৷"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"হোম স্ক্রিনে সেটিংস ও শর্টকাট পড়ুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 346a7ea..0de15da 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliraj prečice"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Dopušta aplikaciji dodavanje prečica bez posredovanja korisnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čita postavke na početnom ekranu i prečice"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 9da16bb..18753ba 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instal·la"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No suggereixis l\'aplicació"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixa la predicció"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instal·la dreceres"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet que una aplicació afegeixi dreceres sense la intervenció de l\'usuari."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"llegir la configuració i les dreceres de la pantalla d\'inici"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 63858d3..e2e5ebf 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Nainstalovat"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovat aplikaci"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Připnout předpověď"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalace zástupce"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Umožňuje aplikaci přidat zástupce bez zásahu uživatele."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čtení nastavení a zkratek plochy"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 99b1bf2..31b6437 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Foreslå ikke en app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fastgør forslaget"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installere genveje"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillader, at en app tilføjer genveje uden brugerens indgriben."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"læs indstillinger og genveje for startskærm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index d052fba..2abbf4c 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installieren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"App nicht vorschlagen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vorgeschlagene App fixieren"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Verknüpfungen installieren"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ermöglicht einer App das Hinzufügen von Verknüpfungen ohne Eingreifen des Nutzers"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Einstellungen und Verknüpfungen auf dem Startbildschirm lesen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 5a178a4..d4322b1 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"εγκατάσταση συντομεύσεων"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ανάγνωση ρυθμίσεων και συντομεύσεων αρχικής οθόνης"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index c9579a5..33a3c4d 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 311b4b9..de41d2c 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
+ <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read home settings and shortcuts"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index c9579a5..33a3c4d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index c9579a5..33a3c4d 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 047a67f..a856340 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
+ <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read home settings and shortcuts"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index f5b4d8a..793e5f2 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación agregue accesos directos sin que el usuario intervenga."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"leer parámetros de configuración y accesos directos de la página principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 92e4a2d0..01b053c 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir aplicación"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"leer ajustes y accesos directos de la pantalla de inicio"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index c2be8cd..231d0f7 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installimine"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ära soovita rakendust"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kinnita ennustus"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installi otseteed"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Võimaldab rakendusel lisada otseteid kasutaja sekkumiseta."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"avakuva seadete ja otseteede lugemine"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 4a9ae90..1c734b1 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalatu"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ez iradoki aplikazioa"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ainguratu iragarpena"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalatu lasterbideak"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Erabiltzaileak ezer egin gabe lasterbideak gehitzeko baimena ematen die aplikazioei."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"irakurri hasierako pantailako ezarpenak eta lasterbideak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 0047f8d..a8a5491 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -48,7 +48,7 @@
<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="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"بایدها"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ضروریات"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"اخبار و مجله"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"سرگرمی"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"اجتماعی"</string>
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"نصب"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"برنامه پیشنهاد داده نشود"</string>
<string name="pin_prediction" msgid="4196423321649756498">"سنجاق کردن پیشنهاد"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"نصب میانبرها"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"به برنامه اجازه میدهد میانبرها را بدون دخالت کاربر اضافه کند."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"خواندن تنظیمات و میانبرهای صفحه اصلی"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 9eaaeb6..0cf15f4 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Asenna"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Älä ehdota sovellusta"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kiinnitä sovellus"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"asenna pikakuvakkeita"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Antaa sovelluksen lisätä pikakuvakkeita itsenäisesti ilman käyttäjän valintaa."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lukea aloitusnäytön asetuksia ja pikakuvakkeita"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 5490ee3..447909a 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une appli d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lire les paramètres et les raccourcis de la page d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 6e04abd..48c3bde 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permettre à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Lire les paramètres et les raccourcis de la page d\'accueil"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index e68d0e5..61a7e3d 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ler a configuración e os atallos da pantalla de inicio"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 92d52a7..b85038c 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
<string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"શૉર્ટકટ ઇન્સ્ટૉલ કરો"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"એપ્લિકેશનને વપરાશકર્તા હસ્તક્ષેપ વગર શોર્ટકટ્સ ઉમેરવાની મંજૂરી આપે છે."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"હોમ સેટિંગ અને શૉર્ટકટ વાંચો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 79fcc3f..1205515 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करें"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ऐप्लिकेशन का सुझाव न दें"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सुझाए गए ऐप पिन करें"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट इंस्टॉल करें"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ऐप को उपयोगकर्ता के हस्तक्षेप के बिना शॉर्टकट जोड़ने देती है."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रीन की सेटिंग और शॉर्टकट पढ़ने की अनुमति"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index eaf1b55..1238172 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prikvači predviđenu apl."</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečaca"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji omogućuje dodavanje prečaca bez intervencije korisnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čitati postavke i prečace početnog zaslona"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index c33cb5a..acd4156 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon appot"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Várható kitűzése"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"parancsikonok telepítése"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül adjon hozzá parancsikonokat."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"kezdőképernyő beállításainak és parancsikonjainak olvasása"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index f06ff83..2c020ad 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Դյուրանցումների տեղադրում"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Հավելվածին թույլ է տալիս ավելացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"կարդալ հիմնական էկրանի կարգավորումներն ու դյուրանցումները"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 8487e62..6586bb4 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"memasang pintasan"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Mengizinkan aplikasi menambahkan pintasan tanpa campur tangan pengguna."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"membaca setelan dan pintasan layar utama"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index ab343e5..f4593ec 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Setja upp"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ekki fá tillögu að forriti"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Festa tillögu"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"setja upp flýtileiðir"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Leyfir forriti að bæta við flýtileiðum án íhlutunar notanda."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lesa stillingar og flýtileiðir heimaskjás"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 378d1e9..a444d21 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installa"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suggerire app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Blocca previsione"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Aggiunta di scorciatoie"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Consente a un\'app di aggiungere scorciatoie automaticamente."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"leggere le impostazioni e le scorciatoie nella schermata Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 2e8cacb..3a45b9f 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"בלי להציע את האפליקציה"</string>
<string name="pin_prediction" msgid="4196423321649756498">"הצמדת החיזוי"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"התקנת קיצורי דרך"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"מאפשר לאפליקציה להוסיף קיצורי דרך ללא התערבות המשתמש."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"קריאת ההגדרות וקיצורי הדרך בדף הבית"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index e0aa65f..9dacea1 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"インストール"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"アプリを表示しない"</string>
<string name="pin_prediction" msgid="4196423321649756498">"アプリの候補を固定"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ショートカットのインストール"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ユーザー操作なしでショートカットを追加することをアプリに許可します。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ホームの設定とショートカットの読み取り"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 1d674cb..9e0e4a9 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"მალსახმობების დაყენება"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"აპისთვის მალსახმობების დამოუკიდებლად დამატების უფლების მიცემა."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების წაკითხვა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 363fc2f..48f3478 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Болжамды бекіту"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"таңбаша орнату"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді қосу мүмкіндігін береді."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"негізгі экран параметрлері мен таңбашаларын оқу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index ab5decf..0044e6a 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ខ្ទាស់ការព្យាករ"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ដំឡើងផ្លូវកាត់"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"អនុញ្ញាតឲ្យកម្មវិធីបន្ថែមផ្លូវកាត់ ដោយមិនចាំបាច់អំពើពីអ្នកប្រើ។"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"អានការកំណត់ និងផ្លូវកាត់របស់អេក្រង់ដើម"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 04daaac..f2d4e55 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ಮುನ್ನೋಟ ಪಿನ್ ಮಾಡಿ"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸ್ಥಾಪಿಸಿ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಓದಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 7aa9e03..f3e5a3a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
<string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"바로가기 설치"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"앱이 사용자의 작업 없이 바로가기를 추가할 수 있도록 합니다."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"홈 설정 및 바로가기 읽기"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index d0079d0..e955666 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнотуу"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Cунушталбасын"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Божомолдонгон колдонмону кадап коюу"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"тез чакырмаларды орнотуу"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Колдонмого колдонуучуга кайрылбастан тез чакырма кошууга уруксат берет."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"үйдүн параметрлерин жана ыкчам баскычтарын окуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 9572f3d..78fe222 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ຢ່າແນະນຳແອັບ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ປັກໝຸດການຄາດເດົາ"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ຕິດຕັ້ງທາງລັດ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ອະນຸຍາດໃຫ້ແອັບຯ ເພີ່ມທາງລັດໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ອ່ານການຕັ້ງຄ່າໜ້າຫຼັກ ແລະ ທາງລັດ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 6cd8872..4954848 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Įdiegti"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nesiūlyti programos"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prisegti numatymą"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"įdiegti sparčiuosius klavišus"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Programai leidžiama pridėti sparčiuosius klavišus be naudotojo įsikišimo."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"skaityti pagrindinio ekrano nustatymus ir sparčiuosius klavišus"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 426fdc0..49e9825 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalēt"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Neieteikt lietotni"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Piespraust prognozēto lietotni"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalēt saīsnes"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ļauj lietotnei pievienot saīsnes, nejautājot lietotājam."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"sākuma ekrāna iestatījumu un saīšņu lasīšana"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index c84f232..626a80e 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање кратенки"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"да чита поставки и кратенки на почетна страница"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index ff06bcf..b777e0f 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -39,7 +39,7 @@
<string name="long_press_widget_to_add" msgid="3587712543577675817">"വിജറ്റ് നീക്കാൻ സ്പർശിച്ച് പിടിക്കുക."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"വിജറ്റ് നീക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യൂ, ഹോൾഡ് ചെയ്യൂ അല്ലെങ്കിൽ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കൂ."</string>
<string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"കൂടുതൽ ഓപ്ഷനുകൾ"</string>
- <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"എല്ലാ വിജറ്റുകളും കാണിക്കൂ"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"എല്ലാ വിജറ്റും കാണിക്കുക"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d വീതിയും %2$d ഉയരവും"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ്"</string>
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
<string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ഹോം ക്രമീകരണവും കുറുക്കുവഴികളും വായിക്കുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index d9b220c..6fe7967 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Апп бүү санал болго"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Таамаглалыг бэхлэх"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"товчлол суулгах"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Апп нь хэрэглэгчийн оролцоогүйгээр товчлолыг нэмэж чадна"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"нүүрний тохиргоо болон товчлолыг унших"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 2f78245..22d789b 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ॲप सुचवू नका"</string>
<string name="pin_prediction" msgid="4196423321649756498">"पूर्वानुमान पिन करा"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट इंस्टॉल करा"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"होम सेटिंग्ज आणि शॉर्टकट वाचा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index d2fd7a8..9320e45 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan cadangkan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Sematkan Ramalan"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"pasang pintasan"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Membenarkan apl menambah pintasan tanpa campur tangan pengguna."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"membaca tetapan dan pintasan skrin utama"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 946d8df..599c9a1 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်အကြံမပြုပါနှင့်"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ခန့်မှန်းချက်ကို ပင်ထိုးရန်"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ဖြတ်လမ်းလင့်ခ်များ ထည့်သွင်းခြင်း"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"အသုံးပြုသူ လုပ်ဆောင်မှုမရှိပဲ အပ်ပလီကေးရှင်းကို အတိုကောက်မှတ်သားမှုများ ပြုလုပ်ခွင့် ပေးခြင်း"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ပင်မဆက်တင်နှင့် ဖြတ်လမ်းလင့်ခ်များ ဖတ်ခြင်း"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 5c0158c..11b076c 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ikke foreslå app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fest forslaget"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installere snarveier"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Gir apper tillatelse til å legge til snarveier uten innblanding fra brukeren."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lese startsideinnstillinger og -snarveier"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index eddcefb..add65ee 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगर्नुहोस्"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सिफारिस गरिएको एप पिन गर्नुहोस्"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रिनका सेटिङ र सर्टकटहरू रिड गर्नुहोस्"</string>
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
index 07c450e..0f630e5 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -57,4 +57,6 @@
@android:color/system_accent1_200</color>
<color name="work_fab_icon_color">
@android:color/system_accent1_900</color>
+
+ <color name="material_color_on_surface">@android:color/system_neutral1_100</color>
</resources>
\ No newline at end of file
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
new file mode 100644
index 0000000..887a2a5
--- /dev/null
+++ b/res/values-night/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <color name="material_color_surface_container_lowest">#0D0E11</color>
+ <color name="material_color_on_surface">#E3E2E6</color>
+</resources>
\ No newline at end of file
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 3402086..c2bc5e0 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installeren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Geen app voorstellen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Voorspelling vastzetten"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelle links instellen"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"instellingen en snelkoppelingen op startscherm lezen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 74001c7..01c6dfc 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ପୂର୍ବାନୁମାନକୁ ପିନ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ସର୍ଟକଟ୍ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ୟୁଜରଙ୍କ ବିନା ହସ୍ତକ୍ଷେପରେ ଶର୍ଟକଟ୍ ଯୋଡ଼ିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ହୋମ ସେଟିଂସ ଏବଂ ସର୍ଟକଟଗୁଡ଼ିକୁ ପଢ଼ନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index e72d1f3..dce05ae 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ਐਪ ਦਾ ਸੁਝਾਅ ਨਾ ਦਿਓ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ਪੂਰਵ-ਅਨੁਮਾਨ ਪਿੰਨ ਕਰੋ"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ਾਰਟਕੱਟ ਸਥਾਪਤ ਕਰੋ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਵਰਤੋਂਕਾਰ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 76ddbdc..fae07369 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Zainstaluj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nie proponuj aplikacji"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Przypnij podpowiedź"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalowanie skrótów"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Pozwala aplikacji dodawać skróty bez interwencji użytkownika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Odczytuje ustawienia i skróty na ekranie głównym"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 1f98805..69b63cf 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma app adicionar atalhos sem a intervenção do utilizador."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ler definições e atalhos do ecrã Principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 20edc93..f4ee373 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir esse app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que um app adicione atalhos sem intervenção do usuário."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ler configurações e atalhos da tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index ec8e558..5293657 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalează"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nu sugera aplicația"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixează predicția"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalează comenzi rapide"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite unei aplicații să adauge comenzi rapide fără intervenția utilizatorului."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"citește setările și comenzile rapide de pe ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index c941cba..0e8faa1 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Создание ярлыков"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Приложение сможет самостоятельно добавлять ярлыки."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Доступ к данным о настройках и ярлыках на главном экране"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 298a078..9db82a7 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"යෙදුම යෝජනා නොකරන්න"</string>
<string name="pin_prediction" msgid="4196423321649756498">"පුරෝකථනය අමුණන්න"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"කෙටිමං ස්ථාපනය කරන්න"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"පරිශීලක මැදිහත්වීමෙන් තොරව කෙටිමං එක් කිරීමට යෙදුමකට අවසර දෙයි."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"මුල් පිටු සැකසීම් සහ කෙටි මං කියවන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 94d109c..5007a7f 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Inštalovať"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovať aplikáciu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pripnúť predpoveď"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"inštalácia odkazov"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Povoľuje aplikácii pridať odkazy bez zásahu používateľa."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čítanie nastavení a odkazov plochy"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 6ee5e07..ab2eff3 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"namestitev bližnjic"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji dovoli dodajanje bližnjic brez posredovanja uporabnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"branje nastavitev in bližnjic na začetnem zaslonu"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index f106fab..a61cd6d 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalo"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Mos sugjero aplikacion"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Gozhdo parashikimin"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalimi i shkurtoreve"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Lejon një aplikacion të shtojë shkurtore pa ndërhyrjen e përdoruesit."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lexo cilësimet dhe shkurtoret e ekranit bazë"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index a9c4e24..621046f 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање пречица"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозвољава апликацији да додаје пречице без интервенције корисника."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"читање подешавања и пречица на почетном екрану"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 5806d1e..812cbd7 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Installera"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Föreslå inte app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fäst förslag"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installera genvägar"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillåter att en app lägger till genvägar utan åtgärd från användaren."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"läsa inställningar och genvägar på startskärmen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 5d69573..5464af3 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Sakinisha"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Isipendekeze programu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Bandika Utabiri"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"kuweka njia za mkato"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Huruhusu programu kuongeza njia za mkato bila mtumiaji kuingilia kati."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"kusoma mipangilio ya skrini ya kwanza na njia za mkato"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 559843a..29ca948 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"பரிந்துரைக்காதே"</string>
<string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்டதைப் பின் செய்"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"முகப்புத் திரையின் அமைப்புகளையும் ஷார்ட்கட்களையும் படித்தல்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index cf18156..038f6b7 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్స్టాల్ చేయండి"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్ సూచించకు"</string>
<string name="pin_prediction" msgid="4196423321649756498">"సూచనను పిన్ చేయండి"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"షార్ట్కట్లను ఇన్స్టాల్ చేయడం"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"వినియోగదారు ప్రమేయం లేకుండా షార్ట్కట్లను జోడించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"హోమ్ సెట్టింగ్లు, షార్ట్కట్లను చదవండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 706c4f4..72684cd 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ติดตั้งทางลัด"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"อนุญาตให้แอปเพิ่มทางลัดโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"อ่านการตั้งค่าและทางลัดในหน้าแรก"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index d99ffdc..ec265c7 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi"</string>
<string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"i-install ang mga shortcut"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Pinapayagan ang isang app na magdagdag ng mga shortcut nang walang panghihimasok ng user."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"basahin ang mga setting at shortcut ng home"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 09939b3..dd4dab6 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"kısayolları yükle"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Uygulamaya, kullanıcı müdahalesi olmadan kısayol ekleme izni verir."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ana ekran ayarlarını ve kısayollarını oku"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 0c9ee22..7048517 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Установити"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не пропонувати додаток"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закріпити передбачений додаток"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"створення ярликів"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозволяє програмі самостійно додавати ярлики."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"читати налаштування та ярлики головного екрана"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 8312ece..8460f73 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ایپ تجویز نہ کریں"</string>
<string name="pin_prediction" msgid="4196423321649756498">"پیشگوئی پن کریں"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"شارٹ کٹس انسٹال کریں"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"کسی ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس شامل کرنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ہوم ترتیبات اور شارٹ کٹس کو پڑھیں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 8f41d49..be02e01 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"O‘rnatish"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tavsiya qilinmasin"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tavsiyani mahkamlash"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"yorliqlar yaratish"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ilovalarga foydalanuvchidan so‘ramasdan yorliqlar qo‘shishga ruxsat beradi."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Bosh ekrandagi sozlamalar va yorliqlarni koʻrish"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 5c81d49..a5cdfc7 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -110,4 +110,6 @@
@android:color/system_accent1_900</color>
<color name="overview_foreground_scrim_color">@android:color/system_neutral1_1000</color>
+
+ <color name="material_color_on_surface">@android:color/system_neutral1_900</color>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index af4a773..3d8b815 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Không gợi ý ứng dụng"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ghim ứng dụng dự đoán"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"cài đặt lối tắt"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Cho phép ứng dụng thêm lối tắt mà không cần sự can thiệp của người dùng."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"đọc lối tắt và các chế độ cài đặt trên màn hình chính"</string>
@@ -129,7 +131,7 @@
<string name="msg_missing_notification_access" msgid="281113995110910548">"Để hiển thị Dấu chấm thông báo, hãy bật thông báo ứng dụng cho <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Thay đổi cài đặt"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"Hiện dấu chấm thông báo"</string>
- <string name="developer_options_title" msgid="700788437593726194">"Tùy chọn cho nhà phát triển"</string>
+ <string name="developer_options_title" msgid="700788437593726194">"Tuỳ chọn cho nhà phát triển"</string>
<string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Thêm biểu tượng ứng dụng vào màn hình chính"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Cho ứng dụng mới"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Không xác định"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3435eb0..12a3a70 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"安装"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要推荐此应用"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定预测的应用"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"安装快捷方式"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"允许应用自行添加快捷方式。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"读取主屏幕设置和快捷方式"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 950d54b..c82a320 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式無需使用者許可也可新增捷徑。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"讀取主畫面設定和捷徑"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 331071d..714fc24 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要建議此應用程式"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式自動新增捷徑。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"讀取主畫面設定和捷徑"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index d167f14..a84b1fb 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -92,6 +92,8 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Faka"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ungaphakamisi uhlelo lokusebenza"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ukubikezela Iphinikhodi"</string>
+ <!-- no translation found for bubble (3072951361014076670) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"faka izinqamuleli"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ivumela uhlelo lokusebenza ukufaka izinqamuleli ngaphandle kokungenelela komsebenzisi."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"funda amasethingi wasekhaya nezinqamuleli"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index c82358b..3f8bede 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -142,6 +142,9 @@
<color name="widget_cell_title_color_dark">@color/system_on_surface_dark</color>
<color name="widget_cell_subtitle_color_dark">@color/system_on_surface_variant_dark</color>
+ <color name="material_color_surface_container_lowest">#FFFFFF</color>
+ <color name="material_color_on_surface">#1B1B1F</color>
+
<color name="system_primary_container_light">#D9E2FF</color>
<color name="system_on_primary_container_light">#001945</color>
<color name="system_primary_light">#475D92</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 2a3b588..507ce9a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -77,6 +77,7 @@
<string name="taskbar_view_callbacks_factory_class" translatable="false"></string>
<string name="launcher_restore_event_logger_class" translatable="false"></string>
<string name="taskbar_edu_tooltip_controller_class" translatable="false"></string>
+ <string name="contextual_edu_manager_class" translatable="false"></string>
<!-- Used for determining category of a widget presented in widget recommendations. -->
<string name="widget_recommendation_category_provider_class" translatable="false"></string>
<string name="api_wrapper_class" translatable="false"></string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index af91b5a..5e1d8a5 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -306,6 +306,7 @@
<dimen name="blur_size_medium_outline">2dp</dimen>
<dimen name="blur_size_click_shadow">4dp</dimen>
<dimen name="click_shadow_high_shift">2dp</dimen>
+ <dimen name="app_title_icon_shadow_inset">1dp</dimen>
<!-- Pending widget -->
<dimen name="pending_widget_min_padding">8dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3b458c2..fd724a5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -215,7 +215,8 @@
<string name="dismiss_prediction_label">Don\'t suggest app</string>
<!-- Label for pinning predicted app. -->
<string name="pin_prediction">Pin Prediction</string>
-
+ <!-- Label for bubbling a launcher item. [CHAR_LIMIT=20] -->
+ <string name="bubble">Bubble</string>
<!-- Permissions: -->
<skip />
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 876b643..d3ee364 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -138,9 +138,6 @@
public static final int TYPE_TOUCH_CONTROLLER_NO_INTERCEPT = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE
& ~TYPE_LISTENER & ~TYPE_TASKBAR_OVERLAYS;
- public static final int TYPE_ALL_EXCEPT_ON_BOARD_POPUP = TYPE_ALL & ~TYPE_ON_BOARD_POPUP
- & ~TYPE_PIN_IME_POPUP;
-
protected boolean mIsOpen;
public AbstractFloatingView(Context context, AttributeSet attrs) {
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 8585b66..177b28c 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -140,15 +140,11 @@
}
protected void onDeviceProfileInitiated() {
- if (mDeviceProfile.isVerticalBarLayout()) {
- mDeviceProfile.updateIsSeascape(this);
- }
}
@Override
public void onDisplayInfoChanged(Context context, Info info, int flags) {
if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.isVerticalBarLayout()) {
- mDeviceProfile.updateIsSeascape(this);
reapplyUi();
}
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 5134dbe..1eccbff 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -504,7 +504,7 @@
mLastOriginalText = label;
mLastModifiedText = mLastOriginalText;
mBreakPointsIntArray = StringMatcherUtility.getListOfBreakpoints(label, MATCHER);
- if (Flags.enableNewArchivingIcon()
+ if (Flags.useNewIconForArchivedApps()
&& info instanceof ItemInfoWithIcon infoWithIcon
&& infoWithIcon.isInactiveArchive()) {
setTextWithArchivingIcon(label);
@@ -820,7 +820,7 @@
getLineSpacingExtra());
if (!TextUtils.equals(modifiedString, mLastModifiedText)) {
mLastModifiedText = modifiedString;
- if (Flags.enableNewArchivingIcon()
+ if (Flags.useNewIconForArchivedApps()
&& getTag() instanceof ItemInfoWithIcon infoWithIcon
&& infoWithIcon.isInactiveArchive()) {
setTextWithArchivingIcon(modifiedString);
@@ -873,7 +873,7 @@
if (drawable == null) {
setText(text);
Log.w(TAG, "setTextWithStartIcon: start icon Drawable not found from resources"
- + ", will just set text instead. text=" + text);
+ + ", will just set text instead.");
return;
}
drawable.setTint(getCurrentTextColor());
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1a5f4b9..5cbf6fb 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -65,7 +65,6 @@
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType;
import com.android.launcher3.responsive.ResponsiveSpecsProvider;
import com.android.launcher3.util.CellContentDimensions;
-import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.IconSizeSteps;
import com.android.launcher3.util.ResourceHelper;
@@ -298,9 +297,6 @@
// the widgetView, such that the actual view size is same as the widget size.
public final Rect widgetPadding = new Rect();
- // When true, nav bar is on the left side of the screen.
- private boolean mIsSeascape;
-
// Notification dots
public final DotRenderer mDotRendererWorkSpace;
public final DotRenderer mDotRendererAllApps;
@@ -2007,25 +2003,8 @@
return isLandscape && transposeLayoutWithOrientation;
}
- /**
- * Updates orientation information and returns true if it has changed from the previous value.
- */
- public boolean updateIsSeascape(Context context) {
- if (isVerticalBarLayout()) {
- boolean isSeascape = DisplayController.INSTANCE.get(context)
- .getInfo().rotation == Surface.ROTATION_270;
- if (mIsSeascape != isSeascape) {
- mIsSeascape = isSeascape;
- // Hotseat changing sides requires updating workspace left/right paddings
- updateWorkspacePadding();
- return true;
- }
- }
- return false;
- }
-
public boolean isSeascape() {
- return isVerticalBarLayout() && mIsSeascape;
+ return rotationHint == Surface.ROTATION_270 && isVerticalBarLayout();
}
public boolean shouldFadeAdjacentWorkspaceScreens() {
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 960d77a..de1748b 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -29,7 +28,6 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -189,10 +187,6 @@
* Scrolls this recycler view to the top.
*/
public void scrollToTop() {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.PRIVATE_SPACE_SCROLL_FAILURE, "FastScrollRecyclerView#scrollToTop",
- new Exception());
- }
if (mScrollbar != null) {
mScrollbar.reattachThumbToScroll();
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 6c706be..fac372b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2708,6 +2708,10 @@
mWidgetPickerDataProvider.dump(prefix, writer);
mDeviceProfile.dump(this, prefix, writer);
mAppsView.getAppsStore().dump(prefix, writer);
+ mAppsView.getPersonalAppList().dump(prefix, writer);
+ if (mAppsView.shouldShowTabs()) {
+ mAppsView.getWorkAppList().dump(prefix, writer);
+ }
try {
FileLog.flushAll(writer);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 08ccfb2..15641ab 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -115,7 +115,7 @@
if (BuildCompat.isAtLeastV() && Flags.enableSupportForArchiving()) {
ArchiveCompatibilityParams params = new ArchiveCompatibilityParams();
params.setEnableUnarchivalConfirmation(false);
- params.setEnableIconOverlay(!Flags.enableNewArchivingIcon());
+ params.setEnableIconOverlay(!Flags.useNewIconForArchivedApps());
launcherApps.setArchiveCompatibility(params);
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index ad660d2..227ac2b 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Flags.enableExpandingPauseWorkButton;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
+import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.WORK;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
@@ -1313,6 +1314,10 @@
return mAH.get(MAIN).mAppsList;
}
+ public AlphabeticalAppsList<T> getWorkAppList() {
+ return mAH.get(WORK).mAppsList;
+ }
+
public FloatingHeaderView getFloatingHeaderView() {
return mHeader;
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 9271596..6dd811a 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -26,6 +26,7 @@
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
+import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -39,6 +40,7 @@
import com.android.launcher3.util.LabelComparator;
import com.android.launcher3.views.ActivityContext;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -270,6 +272,7 @@
List<AdapterItem> oldItems = new ArrayList<>(mAdapterItems);
// Prepare to update the list of sections, filtered apps, etc.
mFastScrollerSections.clear();
+ Log.d(TAG, "Clearing FastScrollerSections.");
mAdapterItems.clear();
mAccessibilityResultsCount = 0;
@@ -290,6 +293,7 @@
mFastScrollerSections.add(new FastScrollSectionInfo(
mActivityContext.getResources().getString(
R.string.work_profile_edu_section), 0));
+ Log.d(TAG, "Adding FastScrollSection for work edu card.");
}
position = addAppsWithSections(mApps, position);
}
@@ -303,6 +307,7 @@
mFastScrollerSections.add(new FastScrollSectionInfo(
mFastScrollerSections.get(mFastScrollerSections.size() - 1).sectionName,
position++));
+ Log.d(TAG, "Adding FastScrollSection duplicate to scroll to the bottom.");
}
}
mAccessibilityResultsCount = (int) mAdapterItems.stream()
@@ -346,6 +351,7 @@
&& !mPrivateApps.isEmpty()) {
// Always add PS Header if Space is present and visible.
position = mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems);
+ Log.d(TAG, "Adding FastScrollSection for Private Space header. ");
mFastScrollerSections.add(new FastScrollSectionInfo(
mPrivateProfileAppScrollerBadge, position));
int privateSpaceState = mPrivateProviderManager.getCurrentState();
@@ -407,14 +413,14 @@
hasPrivateApps = appList.stream().
allMatch(mPrivateProviderManager.getItemInfoMatcher());
}
+ Log.d(TAG, "Adding apps with sections. HasPrivateApps: " + hasPrivateApps);
for (int i = 0; i < appList.size(); i++) {
AppInfo info = appList.get(i);
// Apply decorator to private apps.
if (hasPrivateApps) {
mAdapterItems.add(AdapterItem.asAppWithDecorationInfo(info,
- new SectionDecorationInfo(mActivityContext.getApplicationContext(),
- getRoundRegions(i, appList.size()),
- true /* decorateTogether */)));
+ new SectionDecorationInfo(mActivityContext,
+ getRoundRegions(i, appList.size()), true /* decorateTogether */)));
} else {
mAdapterItems.add(AdapterItem.asApp(info));
}
@@ -422,6 +428,8 @@
String sectionName = info.sectionName;
// Create a new section if the section names do not match
if (!sectionName.equals(lastSectionName)) {
+ Log.d(TAG, "addAppsWithSections: adding sectionName: " + sectionName
+ + " with appInfoTitle: " + info.title);
lastSectionName = sectionName;
mFastScrollerSections.add(new FastScrollSectionInfo(hasPrivateApps ?
mPrivateProfileAppScrollerBadge : sectionName, position));
@@ -472,6 +480,13 @@
return mPrivateProviderManager;
}
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "SectionInfo[] size: " + mFastScrollerSections.size());
+ for (int i = 0; i < mFastScrollerSections.size(); i++) {
+ writer.println("\tFastScrollSection: " + mFastScrollerSections.get(i).sectionName);
+ }
+ }
+
private static class MyDiffCallback extends DiffUtil.Callback {
private final List<AdapterItem> mOldList;
diff --git a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
index 4f8d53e..d593f80 100644
--- a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
+++ b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
@@ -3,6 +3,7 @@
import android.content.Context;
import android.icu.text.AlphabeticIndex;
import android.os.LocaleList;
+import android.util.Log;
import androidx.annotation.NonNull;
@@ -12,6 +13,9 @@
public class AlphabeticIndexCompat {
+ // TODO(b/336947811): Set to false after root causing is done.
+ private static final boolean DEBUG = true;
+ private static final String TAG = "AlphabeticIndexCompat";
private static final String MID_DOT = "\u2219";
private final String mDefaultMiscLabel;
@@ -49,6 +53,9 @@
public String computeSectionName(@NonNull CharSequence cs) {
String s = Utilities.trim(cs);
String sectionName = mBaseIndex.getBucket(mBaseIndex.getBucketIndex(s)).getLabel();
+ if (DEBUG) {
+ Log.d(TAG, "computeSectionName: cs: " + cs + " sectionName: " + sectionName);
+ }
if (Utilities.trim(sectionName).isEmpty() && s.length() > 0) {
int c = s.codePointAt(0);
boolean startsWithDigit = Character.isDigit(c);
diff --git a/src/com/android/launcher3/contextualeducation/ContextualEduStatsManager.java b/src/com/android/launcher3/contextualeducation/ContextualEduStatsManager.java
new file mode 100644
index 0000000..da13546
--- /dev/null
+++ b/src/com/android/launcher3/contextualeducation/ContextualEduStatsManager.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.contextualeducation;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
+import com.android.systemui.contextualeducation.GestureType;
+
+/**
+ * A class to update contextual education data. It is a no-op implementation and could be
+ * overridden by changing the resource value [R.string.contextual_edu_manager_class] to provide
+ * a real implementation.
+ */
+public class ContextualEduStatsManager implements ResourceBasedOverride, SafeCloseable {
+ public static final MainThreadInitializedObject<ContextualEduStatsManager> INSTANCE =
+ forOverride(ContextualEduStatsManager.class, R.string.contextual_edu_manager_class);
+
+ /**
+ * Updates contextual education stats when a gesture is triggered
+ * @param isTrackpadGesture indicates if the gesture is triggered by trackpad
+ * @param gestureType type of gesture triggered
+ */
+ public void updateEduStats(boolean isTrackpadGesture, GestureType gestureType) {
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 6311638..2276ac7 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -41,14 +42,13 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
import com.android.launcher3.Utilities;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.apppairs.AppPairIconDrawingParams;
import com.android.launcher3.apppairs.AppPairIconGraphic;
-import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
@@ -442,10 +442,8 @@
@VisibleForTesting
public void setDrawable(PreviewItemDrawingParams p, ItemInfo item) {
if (item instanceof WorkspaceItemInfo wii) {
- if (wii.hasPromiseIconUi() || (wii.runtimeStatusFlags
- & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
- PreloadIconDrawable drawable = newPendingIcon(mContext, wii);
- p.drawable = drawable;
+ if (isActivePendingIcon(wii)) {
+ p.drawable = newPendingIcon(mContext, wii);
} else {
p.drawable = wii.newIcon(mContext,
Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0);
@@ -463,4 +461,14 @@
// callback will be released when the folder is opened.
p.drawable.setCallback(mIcon);
}
+
+ /**
+ * Returns true if item is a Promise Icon or actively downloading, and the item is not an
+ * inactive archived app.
+ */
+ private boolean isActivePendingIcon(WorkspaceItemInfo item) {
+ return (item.hasPromiseIconUi()
+ || (item.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0)
+ && !(Flags.useNewIconForArchivedApps() && item.isInactiveArchive());
+ }
}
diff --git a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
index 480e8f3..ec0efe0 100644
--- a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
@@ -199,6 +199,10 @@
}
protected void changeFocus(T item, boolean hasFocus) {
+ if (mLastFocusedItem != item && !hasFocus) {
+ return;
+ }
+
if (hasFocus) {
endCurrentAnimation();
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 7e1d40d..da1a221 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -83,6 +83,7 @@
import org.xmlpull.v1.XmlPullParser;
+import java.io.File;
import java.io.InputStream;
import java.io.StringReader;
@@ -104,10 +105,30 @@
mContext = context;
}
+ private void printDBs(String prefix) {
+ try {
+ File directory = new File(
+ mContext.getDatabasePath(InvariantDeviceProfile.INSTANCE.get(mContext).dbFile)
+ .getParent()
+ );
+ if (directory.exists()) {
+ for (File file : directory.listFiles()) {
+ Log.d("b/353505773", prefix + "Database file: " + file.getName());
+ }
+ } else {
+ Log.d("b/353505773", prefix + "No files found in the database directory");
+ }
+ } catch (Exception e) {
+ Log.e("b/353505773", prefix + e.getMessage());
+ }
+ }
+
private synchronized void createDbIfNotExists() {
if (mOpenHelper == null) {
mOpenHelper = createDatabaseHelper(false /* forMigration */);
+ printDBs("before: ");
RestoreDbTask.restoreIfNeeded(mContext, this);
+ printDBs("after: ");
}
}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 35064cf..c949ce6 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -89,7 +89,7 @@
if (!WIDGETS_ENABLED) {
return Collections.emptyMap();
}
- return mWidgetsByPackageItem;
+ return new HashMap<>(mWidgetsByPackageItem);
}
/**
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 40e3813..f31bf1e 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -25,6 +25,7 @@
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
@@ -97,6 +98,8 @@
public int options;
+ @Nullable
+ private ShortcutInfo mShortcutInfo = null;
public WorkspaceItemInfo() {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
@@ -175,6 +178,9 @@
public void updateFromDeepShortcutInfo(@NonNull final ShortcutInfo shortcutInfo,
@NonNull final Context context) {
+ if (com.android.wm.shell.Flags.enableBubbleAnything()) {
+ mShortcutInfo = shortcutInfo;
+ }
// {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent
intent = ShortcutKey.makeIntent(shortcutInfo);
title = shortcutInfo.getShortLabel();
@@ -204,6 +210,11 @@
: Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);
}
+ @Nullable
+ public ShortcutInfo getDeepShortcutInfo() {
+ return mShortcutInfo;
+ }
+
/**
* {@code true} if the shortcut is disabled due to its app being a lower version.
*/
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index f7e1168..0c90eb9 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -11,9 +11,11 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Process;
import android.os.UserHandle;
+import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
@@ -25,6 +27,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.AbstractFloatingViewHelper;
import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.SecondaryDropTarget;
import com.android.launcher3.Utilities;
@@ -53,6 +56,7 @@
*/
public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo
implements View.OnClickListener {
+ private static final String TAG = "SystemShortcut";
private final int mIconResId;
protected final int mLabelResId;
@@ -383,4 +387,63 @@
mAbstractFloatingViewHelper.closeOpenViews(mTarget, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
}
+
+ public static final Factory<ActivityContext> BUBBLE_SHORTCUT =
+ (activity, itemInfo, originalView) -> {
+ if ((itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+ && (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION)
+ && !(itemInfo instanceof WorkspaceItemInfo)) {
+ return null;
+ }
+ return new BubbleShortcut(activity, itemInfo, originalView);
+ };
+
+ public interface BubbleActivityStarter {
+ /** Tell SysUI to show the provided shortcut in a bubble. */
+ void showShortcutBubble(ShortcutInfo info);
+
+ /** Tell SysUI to show the provided intent in a bubble. */
+ void showAppBubble(Intent intent);
+ }
+
+ public static class BubbleShortcut<T extends ActivityContext> extends SystemShortcut<T> {
+
+ private BubbleActivityStarter mStarter;
+
+ public BubbleShortcut(T target, ItemInfo itemInfo, View originalView) {
+ super(R.drawable.ic_bubble_button, R.string.bubble, target,
+ itemInfo, originalView);
+ if (target instanceof BubbleActivityStarter) {
+ mStarter = (BubbleActivityStarter) target;
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ dismissTaskMenuView();
+ if (mStarter == null) {
+ Log.w(TAG, "starter null!");
+ return;
+ }
+ // TODO: handle GroupTask (single) items so that recent items in taskbar work
+ if (mItemInfo instanceof WorkspaceItemInfo) {
+ WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo;
+ ShortcutInfo shortcutInfo = workspaceItemInfo.getDeepShortcutInfo();
+ if (shortcutInfo != null) {
+ mStarter.showShortcutBubble(shortcutInfo);
+ return;
+ }
+ }
+ // If we're here check for an intent
+ Intent intent = mItemInfo.getIntent();
+ if (intent != null) {
+ if (intent.getPackage() == null) {
+ intent.setPackage(mItemInfo.getTargetPackage());
+ }
+ mStarter.showAppBubble(intent);
+ } else {
+ Log.w(TAG, "unable to bubble, no intent: " + mItemInfo);
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index f895b30..6ff51ca 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -17,13 +17,12 @@
package com.android.launcher3.recyclerview
import android.content.Context
-import android.view.ViewGroup
-import androidx.annotation.VisibleForTesting
-import androidx.annotation.VisibleForTesting.Companion.PROTECTED
+import android.util.Log
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.android.launcher3.BubbleTextView
+import com.android.launcher3.BuildConfig
import com.android.launcher3.allapps.BaseAllAppsAdapter
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.util.CancellableTask
@@ -41,18 +40,36 @@
* [RecyclerView]. The view inflation will happen on background thread and inflated [ViewHolder]s
* will be added to [RecycledViewPool] on main thread.
*/
-class AllAppsRecyclerViewPool<T> : RecycledViewPool() where T : Context, T : ActivityContext {
+class AllAppsRecyclerViewPool<T> : RecycledViewPool() {
var hasWorkProfile = false
- @VisibleForTesting(otherwise = PROTECTED)
- var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
+ private var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
+
+ companion object {
+ private const val TAG = "AllAppsRecyclerViewPool"
+ private const val NULL_LAYOUT_MANAGER_ERROR_STRING =
+ "activeRv's layoutManager should not be null"
+ }
/**
* Preinflate app icons. If all apps RV cannot be scrolled down, we don't need to preinflate.
*/
- fun preInflateAllAppsViewHolders(context: T) {
+ fun <T> preInflateAllAppsViewHolders(context: T) where T : Context, T : ActivityContext {
val appsView = context.appsView ?: return
val activeRv: RecyclerView = appsView.activeRecyclerView ?: return
+ val preInflateCount = getPreinflateCount(context)
+ if (preInflateCount <= 0) {
+ return
+ }
+
+ if (activeRv.layoutManager == null) {
+ if (BuildConfig.IS_STUDIO_BUILD) {
+ throw IllegalStateException(NULL_LAYOUT_MANAGER_ERROR_STRING)
+ } else {
+ Log.e(TAG, NULL_LAYOUT_MANAGER_ERROR_STRING)
+ }
+ return
+ }
// Create a separate context dedicated for all apps preinflation thread. The goal is to
// create a separate AssetManager obj internally to avoid lock contention with
@@ -81,47 +98,36 @@
override fun getLayoutManager(): RecyclerView.LayoutManager? = null
}
- preInflateAllAppsViewHolders(adapter, BaseAllAppsAdapter.VIEW_TYPE_ICON, activeRv) {
- getPreinflateCount(context)
- }
- }
-
- @VisibleForTesting(otherwise = PROTECTED)
- fun preInflateAllAppsViewHolders(
- adapter: RecyclerView.Adapter<*>,
- viewType: Int,
- parent: ViewGroup,
- preInflationCountProvider: () -> Int
- ) {
- val preinflationCount = preInflationCountProvider.invoke()
- if (preinflationCount <= 0) {
- return
- }
mCancellableTask?.cancel()
var task: CancellableTask<List<ViewHolder>>? = null
task =
CancellableTask(
{
val list: ArrayList<ViewHolder> = ArrayList()
- for (i in 0 until preinflationCount) {
+ for (i in 0 until preInflateCount) {
if (task?.canceled == true) {
break
}
- list.add(adapter.createViewHolder(parent, viewType))
+ // If activeRv's layout manager has been reset to null on main thread, skip
+ // the preinflation as we cannot generate correct LayoutParams
+ if (activeRv.layoutManager == null) {
+ break
+ }
+ list.add(
+ adapter.createViewHolder(activeRv, BaseAllAppsAdapter.VIEW_TYPE_ICON)
+ )
}
list
},
MAIN_EXECUTOR,
{ viewHolders ->
- // Run preInflationCountProvider again as the needed VH might have changed
- val newPreinflationCount = preInflationCountProvider.invoke()
- for (i in 0 until minOf(viewHolders.size, newPreinflationCount)) {
+ for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) {
putRecycledView(viewHolders[i])
}
}
)
mCancellableTask = task
- VIEW_PREINFLATION_EXECUTOR.execute(mCancellableTask)
+ VIEW_PREINFLATION_EXECUTOR.submit(mCancellableTask)
}
/**
@@ -142,7 +148,7 @@
* app icons in size of one all apps pages, so that opening all apps don't need to inflate app
* icons.
*/
- fun getPreinflateCount(context: T): Int {
+ fun <T> getPreinflateCount(context: T): Int where T : Context, T : ActivityContext {
var targetPreinflateCount =
PREINFLATE_ICONS_ROW_COUNT * context.deviceProfile.numShownAllAppsColumns +
EXTRA_ICONS_COUNT
diff --git a/src/com/android/launcher3/util/DimensionUtils.kt b/src/com/android/launcher3/util/DimensionUtils.kt
index 63e919a..821dda7 100644
--- a/src/com/android/launcher3/util/DimensionUtils.kt
+++ b/src/com/android/launcher3/util/DimensionUtils.kt
@@ -31,7 +31,8 @@
fun getTaskbarPhoneDimensions(
deviceProfile: DeviceProfile,
res: Resources,
- isPhoneMode: Boolean
+ isPhoneMode: Boolean,
+ isGestureNav: Boolean,
): Point {
val p = Point()
// Taskbar for large screen
@@ -42,7 +43,7 @@
}
// Taskbar on phone using gesture nav, it will always be stashed
- if (deviceProfile.isGestureMode) {
+ if (isGestureNav) {
p.x = ViewGroup.LayoutParams.MATCH_PARENT
p.y = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size)
return p
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 95624b1..837d7bc 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -186,12 +186,6 @@
public int stagePosition = STAGE_POSITION_UNDEFINED;
@StageType
public int stageType = STAGE_TYPE_UNDEFINED;
-
- @Override
- public String toString() {
- return "SplitStageInfo { taskId=" + taskId
- + ", stagePosition=" + stagePosition + ", stageType=" + stageType + " }";
- }
}
public static StatsLogManager.EventEnum getLogEventForPosition(@StagePosition int position) {
diff --git a/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
new file mode 100644
index 0000000..e9691a8
--- /dev/null
+++ b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.coroutines
+
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+
+interface DispatcherProvider {
+ val default: CoroutineDispatcher
+ val io: CoroutineDispatcher
+ val main: CoroutineDispatcher
+ val unconfined: CoroutineDispatcher
+}
+
+object ProductionDispatchers : DispatcherProvider {
+ override val default: CoroutineDispatcher = Dispatchers.Default
+ override val io: CoroutineDispatcher = Dispatchers.IO
+ override val main: CoroutineDispatcher = Dispatchers.Main
+ override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined
+}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index bc66a33..ef66ffe 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -19,11 +19,19 @@
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
import android.util.AttributeSet;
-import android.widget.TextView;
+import android.util.Log;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
@@ -45,22 +53,65 @@
public DoubleShadowBubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mShadowInfo = new ShadowInfo(context, attrs, defStyle);
- setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0, mShadowInfo.ambientShadowColor);
+ mShadowInfo = ShadowInfo.Companion.fromContext(context, attrs, defStyle);
+ setShadowLayer(
+ mShadowInfo.getAmbientShadowBlur(),
+ 0,
+ 0,
+ mShadowInfo.getAmbientShadowColor()
+ );
+ }
+
+ @Override
+ public void setTextWithStartIcon(CharSequence text, @DrawableRes int drawableId) {
+ Drawable drawable = getContext().getDrawable(drawableId);
+ if (drawable == null) {
+ setText(text);
+ Log.w(TAG, "setTextWithStartIcon: start icon Drawable not found from resources"
+ + ", will just set text instead.");
+ return;
+ }
+ drawable.setTint(getCurrentTextColor());
+ int textSize = Math.round(getTextSize());
+ ImageSpan imageSpan;
+ if (!skipDoubleShadow() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ drawable = getDoubleShadowDrawable(drawable, textSize);
+ }
+ drawable.setBounds(0, 0, textSize, textSize);
+ imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_CENTER);
+ // First space will be replaced with Drawable, second space is for space before text.
+ SpannableString spannable = new SpannableString(" " + text);
+ spannable.setSpan(imageSpan, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+ setText(spannable);
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ private DoubleShadowIconDrawable getDoubleShadowDrawable(
+ @NonNull Drawable drawable, int textSize
+ ) {
+ // add some padding via inset to avoid shadow clipping
+ int iconInsetSize = getContext().getResources()
+ .getDimensionPixelSize(R.dimen.app_title_icon_shadow_inset);
+ return new DoubleShadowIconDrawable(
+ mShadowInfo,
+ drawable,
+ textSize,
+ iconInsetSize
+ );
}
@Override
public void onDraw(Canvas canvas) {
// If text is transparent or shadow alpha is 0, don't draw any shadow
- if (mShadowInfo.skipDoubleShadow(this)) {
+ if (skipDoubleShadow()) {
super.onDraw(canvas);
return;
}
int alpha = Color.alpha(getCurrentTextColor());
// We enhance the shadow by drawing the shadow twice
- getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0,
- getTextShadowColor(mShadowInfo.ambientShadowColor, alpha));
+ getPaint().setShadowLayer(mShadowInfo.getAmbientShadowBlur(), 0, 0,
+ getTextShadowColor(mShadowInfo.getAmbientShadowColor(), alpha));
drawWithoutDot(canvas);
canvas.save();
@@ -69,10 +120,10 @@
getScrollY() + getHeight());
getPaint().setShadowLayer(
- mShadowInfo.keyShadowBlur,
- mShadowInfo.keyShadowOffsetX,
- mShadowInfo.keyShadowOffsetY,
- getTextShadowColor(mShadowInfo.keyShadowColor, alpha));
+ mShadowInfo.getKeyShadowBlur(),
+ mShadowInfo.getKeyShadowOffsetX(),
+ mShadowInfo.getKeyShadowOffsetY(),
+ getTextShadowColor(mShadowInfo.getKeyShadowColor(), alpha));
drawWithoutDot(canvas);
canvas.restore();
@@ -80,55 +131,30 @@
drawRunningAppIndicatorIfNecessary(canvas);
}
- public static class ShadowInfo {
- public final float ambientShadowBlur;
- public final int ambientShadowColor;
-
- public final float keyShadowBlur;
- public final float keyShadowOffsetX;
- public final float keyShadowOffsetY;
- public final int keyShadowColor;
-
- public ShadowInfo(Context c, AttributeSet attrs, int defStyle) {
-
- TypedArray a = c.obtainStyledAttributes(
- attrs, R.styleable.ShadowInfo, defStyle, 0);
-
- ambientShadowBlur = a.getDimensionPixelSize(
- R.styleable.ShadowInfo_ambientShadowBlur, 0);
- ambientShadowColor = a.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0);
-
- keyShadowBlur = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowBlur, 0);
- keyShadowOffsetX = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetX, 0);
- keyShadowOffsetY = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetY, 0);
- keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
- a.recycle();
- }
-
- public boolean skipDoubleShadow(TextView textView) {
- int textAlpha = Color.alpha(textView.getCurrentTextColor());
- int keyShadowAlpha = Color.alpha(keyShadowColor);
- int ambientShadowAlpha = Color.alpha(ambientShadowColor);
- if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
- textView.getPaint().clearShadowLayer();
- return true;
- } else if (ambientShadowAlpha > 0 && keyShadowAlpha == 0) {
- textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
- getTextShadowColor(ambientShadowColor, textAlpha));
- return true;
- } else if (keyShadowAlpha > 0 && ambientShadowAlpha == 0) {
- textView.getPaint().setShadowLayer(
- keyShadowBlur,
- keyShadowOffsetX,
- keyShadowOffsetY,
- getTextShadowColor(keyShadowColor, textAlpha));
- return true;
- } else {
- return false;
- }
+ private boolean skipDoubleShadow() {
+ int textAlpha = Color.alpha(getCurrentTextColor());
+ int keyShadowAlpha = Color.alpha(mShadowInfo.getKeyShadowColor());
+ int ambientShadowAlpha = Color.alpha(mShadowInfo.getAmbientShadowColor());
+ if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
+ getPaint().clearShadowLayer();
+ return true;
+ } else if (ambientShadowAlpha > 0 && keyShadowAlpha == 0) {
+ getPaint().setShadowLayer(mShadowInfo.getAmbientShadowBlur(), 0, 0,
+ getTextShadowColor(mShadowInfo.getAmbientShadowColor(), textAlpha));
+ return true;
+ } else if (keyShadowAlpha > 0 && ambientShadowAlpha == 0) {
+ getPaint().setShadowLayer(
+ mShadowInfo.getKeyShadowBlur(),
+ mShadowInfo.getKeyShadowOffsetX(),
+ mShadowInfo.getKeyShadowOffsetY(),
+ getTextShadowColor(mShadowInfo.getKeyShadowColor(), textAlpha));
+ return true;
+ } else {
+ return false;
}
}
+
// Multiplies the alpha of shadowColor by textAlpha.
private static int getTextShadowColor(int shadowColor, int textAlpha) {
return setColorAlphaBound(shadowColor,
diff --git a/src/com/android/launcher3/views/DoubleShadowIconDrawable.kt b/src/com/android/launcher3/views/DoubleShadowIconDrawable.kt
new file mode 100644
index 0000000..7ac7c94
--- /dev/null
+++ b/src/com/android/launcher3/views/DoubleShadowIconDrawable.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.views
+
+import android.content.res.ColorStateList
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.PixelFormat
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
+import android.graphics.Shader
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.InsetDrawable
+import android.os.Build.VERSION_CODES
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+
+/**
+ * Launcher wrapper for Drawables to provide a double shadow effect. Currently for use with
+ * [DoubleShadowBubbleTextView] to provide a similar shadow to inline icons.
+ */
+@RequiresApi(VERSION_CODES.S)
+class DoubleShadowIconDrawable(
+ private val shadowInfo: ShadowInfo,
+ iconDrawable: Drawable,
+ private val iconSize: Int,
+ iconInsetSize: Int
+) : Drawable() {
+ private val mIconDrawable: InsetDrawable
+ private val mDoubleShadowNode: RenderNode?
+
+ init {
+ mIconDrawable = InsetDrawable(iconDrawable, iconInsetSize)
+ mIconDrawable.setBounds(0, 0, iconSize, iconSize)
+ mDoubleShadowNode = createShadowRenderNode()
+ }
+
+ @VisibleForTesting
+ fun createShadowRenderNode(): RenderNode {
+ val renderNode = RenderNode("DoubleShadowNode")
+ renderNode.setPosition(0, 0, iconSize, iconSize)
+ // Create render effects
+ val ambientShadow =
+ createShadowRenderEffect(
+ shadowInfo.ambientShadowBlur,
+ 0f,
+ 0f,
+ Color.alpha(shadowInfo.ambientShadowColor).toFloat()
+ )
+ val keyShadow =
+ createShadowRenderEffect(
+ shadowInfo.keyShadowBlur,
+ shadowInfo.keyShadowOffsetX,
+ shadowInfo.keyShadowOffsetY,
+ Color.alpha(shadowInfo.keyShadowColor).toFloat()
+ )
+ val blend = RenderEffect.createBlendModeEffect(ambientShadow, keyShadow, BlendMode.DST_ATOP)
+ renderNode.setRenderEffect(blend)
+ return renderNode
+ }
+
+ @VisibleForTesting
+ fun createShadowRenderEffect(
+ radius: Float,
+ offsetX: Float,
+ offsetY: Float,
+ alpha: Float
+ ): RenderEffect {
+ return RenderEffect.createColorFilterEffect(
+ PorterDuffColorFilter(Color.argb(alpha, 0f, 0f, 0f), PorterDuff.Mode.MULTIPLY),
+ RenderEffect.createOffsetEffect(
+ offsetX,
+ offsetY,
+ RenderEffect.createBlurEffect(radius, radius, Shader.TileMode.CLAMP)
+ )
+ )
+ }
+
+ override fun draw(canvas: Canvas) {
+ if (canvas.isHardwareAccelerated && mDoubleShadowNode != null) {
+ if (!mDoubleShadowNode.hasDisplayList()) {
+ // Record render node if its display list is not recorded or discarded
+ // (which happens when it's no longer drawn by anything).
+ val recordingCanvas = mDoubleShadowNode.beginRecording()
+ mIconDrawable.draw(recordingCanvas)
+ mDoubleShadowNode.endRecording()
+ }
+ canvas.drawRenderNode(mDoubleShadowNode)
+ }
+ mIconDrawable.draw(canvas)
+ }
+
+ override fun getIntrinsicHeight() = iconSize
+
+ override fun getIntrinsicWidth() = iconSize
+
+ override fun getOpacity() = PixelFormat.TRANSPARENT
+
+ override fun setAlpha(alpha: Int) {
+ mIconDrawable.alpha = alpha
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ mIconDrawable.colorFilter = colorFilter
+ }
+
+ override fun setTint(color: Int) {
+ mIconDrawable.setTint(color)
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ mIconDrawable.setTintList(tint)
+ }
+}
diff --git a/src/com/android/launcher3/views/ShadowInfo.kt b/src/com/android/launcher3/views/ShadowInfo.kt
new file mode 100644
index 0000000..4f626ec
--- /dev/null
+++ b/src/com/android/launcher3/views/ShadowInfo.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.views
+
+import android.content.Context
+import android.util.AttributeSet
+import com.android.launcher3.R
+
+/**
+ * Launcher data holder for classes such as [DoubleShadowBubbleTextView] to model shadows for
+ * "double shadow" effect.
+ */
+data class ShadowInfo(
+ val ambientShadowBlur: Float,
+ val ambientShadowColor: Int,
+ val keyShadowBlur: Float,
+ val keyShadowOffsetX: Float,
+ val keyShadowOffsetY: Float,
+ val keyShadowColor: Int
+) {
+
+ companion object {
+ /** Constructs instance of ShadowInfo from Context and given attribute set. */
+ @JvmStatic
+ fun fromContext(context: Context, attrs: AttributeSet?, defStyle: Int): ShadowInfo {
+ val styledAttrs =
+ context.obtainStyledAttributes(attrs, R.styleable.ShadowInfo, defStyle, 0)
+ val shadowInfo =
+ ShadowInfo(
+ ambientShadowBlur =
+ styledAttrs
+ .getDimensionPixelSize(R.styleable.ShadowInfo_ambientShadowBlur, 0)
+ .toFloat(),
+ ambientShadowColor =
+ styledAttrs.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0),
+ keyShadowBlur =
+ styledAttrs
+ .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowBlur, 0)
+ .toFloat(),
+ keyShadowOffsetX =
+ styledAttrs
+ .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetX, 0)
+ .toFloat(),
+ keyShadowOffsetY =
+ styledAttrs
+ .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetY, 0)
+ .toFloat(),
+ keyShadowColor = styledAttrs.getColor(R.styleable.ShadowInfo_keyShadowColor, 0)
+ )
+ styledAttrs.recycle()
+ return shadowInfo
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
index 71d8503..91b899c 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
@@ -24,6 +24,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.util.Executors;
@@ -77,6 +78,11 @@
mViewToRecycle = viewToRecycle;
}
+ @VisibleForTesting
+ @Nullable ListenableHostView getViewToRecycle() {
+ return mViewToRecycle;
+ }
+
@Override
@NonNull
public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
diff --git a/tests/Android.bp b/tests/Android.bp
index e51242f..c99f656 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -71,6 +71,9 @@
// Library with all the dependencies for building quickstep
android_library {
name: "Launcher3TestLib",
+ defaults: [
+ "launcher_compose_tests_defaults",
+ ],
srcs: [],
asset_dirs: ["assets"],
resource_dirs: ["res"],
@@ -112,6 +115,9 @@
android_test {
name: "Launcher3Tests",
+ defaults: [
+ "launcher_compose_tests_defaults",
+ ],
srcs: [
":launcher-tests-src",
":launcher-non-quickstep-tests-src",
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index dc3b321..3f4a73a 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -173,8 +173,6 @@
public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
- public static final String PRIVATE_SPACE_SCROLL_FAILURE = "b/339737008";
-
public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
index c32461e..a3c7f4f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
@@ -104,7 +104,7 @@
val cl = cellLayoutBuilder.createCellLayout(board.width, board.height, false)
// The views have to be sorted or the result can vary
board.icons
- .map(IconPoint::getCoord)
+ .map(IconPoint::coord)
.sortedWith(
Comparator.comparing { p: Any -> (p as Point).x }
.thenComparing { p: Any -> (p as Point).y }
@@ -120,9 +120,7 @@
)
}
board.widgets
- .sortedWith(
- Comparator.comparing(WidgetRect::getCellX).thenComparing(WidgetRect::getCellY)
- )
+ .sortedWith(Comparator.comparing(WidgetRect::cellX).thenComparing(WidgetRect::cellY))
.forEach { widget ->
addViewInCellLayout(
cl,
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/BoardClasses.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/BoardClasses.kt
new file mode 100644
index 0000000..3cbfc5a
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/BoardClasses.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.celllayout.board
+
+import android.graphics.Point
+import android.graphics.Rect
+
+/** Represents a widget in a CellLayoutBoard */
+data class WidgetRect(
+ val type: Char,
+ val bounds: Rect,
+) {
+ val spanX: Int = bounds.right - bounds.left + 1
+ val spanY: Int = bounds.top - bounds.bottom + 1
+ val cellY: Int = bounds.bottom
+ val cellX: Int = bounds.left
+
+ fun shouldIgnore() = type == CellType.IGNORE
+
+ fun contains(x: Int, y: Int) = bounds.contains(x, y)
+}
+
+/**
+ * [A-Z]: Represents a folder and number of icons in the folder is represented by the order of
+ * letter in the alphabet, A=2, B=3, C=4 ... etc.
+ */
+data class FolderPoint(val coord: Point, val type: Char) {
+ val numberIconsInside: Int = type.code - 'A'.code + 2
+}
+
+/** Represents an icon in a CellLayoutBoard */
+data class IconPoint(val coord: Point, val type: Char = CellType.ICON)
+
+object CellType {
+ // The cells marked by this will be filled by 1x1 widgets and will be ignored when
+ // validating
+ const val IGNORE = 'x'
+
+ // The cells marked by this will be filled by app icons
+ const val ICON = 'i'
+
+ // The cells marked by FOLDER will be filled by folders with 27 app icons inside
+ const val FOLDER = 'Z'
+
+ // Empty space
+ const val EMPTY = '-'
+
+ // Widget that will be saved as "main widget" for easier retrieval
+ const val MAIN_WIDGET = 'm' // Everything else will be consider a widget
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
index e5ad888..04bfee9 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
@@ -88,7 +88,7 @@
public WidgetRect getWidgetOfType(char type) {
return mWidgetsRects.stream()
- .filter(widgetRect -> widgetRect.mType == type).findFirst().orElse(null);
+ .filter(widgetRect -> widgetRect.getType() == type).findFirst().orElse(null);
}
public WidgetRect getWidgetAt(int x, int y) {
@@ -117,8 +117,8 @@
}
private void removeWidgetFromBoard(WidgetRect widget) {
- for (int xi = widget.mBounds.left; xi <= widget.mBounds.right; xi++) {
- for (int yi = widget.mBounds.bottom; yi <= widget.mBounds.top; yi++) {
+ for (int xi = widget.getBounds().left; xi <= widget.getBounds().right; xi++) {
+ for (int yi = widget.getBounds().bottom; yi <= widget.getBounds().top; yi++) {
mWidget[xi][yi] = '-';
}
}
@@ -127,7 +127,7 @@
private void removeOverlappingItems(Rect rect) {
// Remove overlapping widgets and remove them from the board
mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
- if (rect.intersect(widget.mBounds)) {
+ if (rect.intersect(widget.getBounds())) {
removeWidgetFromBoard(widget);
return false;
}
@@ -135,8 +135,8 @@
}).collect(Collectors.toList());
// Remove overlapping icons and remove them from the board
mIconPoints = mIconPoints.stream().filter(iconPoint -> {
- int x = iconPoint.coord.x;
- int y = iconPoint.coord.y;
+ int x = iconPoint.getCoord().x;
+ int y = iconPoint.getCoord().y;
if (rect.contains(x, y)) {
mWidget[x][y] = '-';
return false;
@@ -146,8 +146,8 @@
// Remove overlapping folders and remove them from the board
mFolderPoints = mFolderPoints.stream().filter(folderPoint -> {
- int x = folderPoint.coord.x;
- int y = folderPoint.coord.y;
+ int x = folderPoint.getCoord().x;
+ int y = folderPoint.getCoord().y;
if (rect.contains(x, y)) {
mWidget[x][y] = '-';
return false;
@@ -159,7 +159,7 @@
private void removeOverlappingItems(Point p) {
// Remove overlapping widgets and remove them from the board
mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
- if (IdenticalBoardComparator.Companion.touchesPoint(widget.mBounds, p)) {
+ if (IdenticalBoardComparator.Companion.touchesPoint(widget.getBounds(), p)) {
removeWidgetFromBoard(widget);
return false;
}
@@ -167,8 +167,8 @@
}).collect(Collectors.toList());
// Remove overlapping icons and remove them from the board
mIconPoints = mIconPoints.stream().filter(iconPoint -> {
- int x = iconPoint.coord.x;
- int y = iconPoint.coord.y;
+ int x = iconPoint.getCoord().x;
+ int y = iconPoint.getCoord().y;
if (p.x == x && p.y == y) {
mWidget[x][y] = '-';
return false;
@@ -178,8 +178,8 @@
// Remove overlapping folders and remove them from the board
mFolderPoints = mFolderPoints.stream().filter(folderPoint -> {
- int x = folderPoint.coord.x;
- int y = folderPoint.coord.y;
+ int x = folderPoint.getCoord().x;
+ int y = folderPoint.getCoord().y;
if (p.x == x && p.y == y) {
mWidget[x][y] = '-';
return false;
@@ -226,7 +226,7 @@
public void removeItem(char type) {
mWidgetsRects.stream()
- .filter(widgetRect -> widgetRect.mType == type)
+ .filter(widgetRect -> widgetRect.getType() == type)
.forEach(widgetRect -> removeOverlappingItems(
new Point(widgetRect.getCellX(), widgetRect.getCellY())));
}
@@ -365,10 +365,10 @@
board.mWidth = lines[0].length();
board.mWidgetsRects = getRects(board.mWidget);
board.mWidgetsRects.forEach(widgetRect -> {
- if (widgetRect.mType == CellType.MAIN_WIDGET) {
+ if (widgetRect.getType() == CellType.MAIN_WIDGET) {
board.mMain = widgetRect;
}
- board.mWidgetsMap.put(widgetRect.mType, widgetRect);
+ board.mWidgetsMap.put(widgetRect.getType(), widgetRect);
});
board.mIconPoints = getIconPoints(board.mWidget);
board.mFolderPoints = getFolderPoints(board.mWidget);
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java
deleted file mode 100644
index 49c146b..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-public class CellType {
- // The cells marked by this will be filled by 1x1 widgets and will be ignored when
- // validating
- public static final char IGNORE = 'x';
- // The cells marked by this will be filled by app icons
- public static final char ICON = 'i';
- // The cells marked by FOLDER will be filled by folders with 27 app icons inside
- public static final char FOLDER = 'Z';
- // Empty space
- public static final char EMPTY = '-';
- // Widget that will be saved as "main widget" for easier retrieval
- public static final char MAIN_WIDGET = 'm';
- // Everything else will be consider a widget
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java
deleted file mode 100644
index 39ba434..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-import android.graphics.Point;
-
-public class FolderPoint {
- public Point coord;
- public char mType;
-
- public FolderPoint(Point coord, char type) {
- this.coord = coord;
- mType = type;
- }
-
- /**
- * [A-Z]: Represents a folder and number of icons in the folder is represented by
- * the order of letter in the alphabet, A=2, B=3, C=4 ... etc.
- */
- public int getNumberIconsInside() {
- return (mType - 'A') + 2;
- }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java
deleted file mode 100644
index d3d2970..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-import android.graphics.Point;
-
-public class IconPoint {
- public Point coord;
- public char mType;
-
- public IconPoint(Point coord, char type) {
- this.coord = coord;
- mType = type;
- }
-
- public char getType() {
- return mType;
- }
-
- public void setType(char type) {
- mType = type;
- }
-
- public Point getCoord() {
- return coord;
- }
-
- public void setCoord(Point coord) {
- this.coord = coord;
- }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
index a4a420c..aacd940 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
@@ -26,11 +26,11 @@
/** Converts a list of WidgetRect into a map of the count of different widget.bounds */
private fun widgetsToBoundsMap(widgets: List<WidgetRect>) =
- widgets.groupingBy { it.mBounds }.eachCount()
+ widgets.groupingBy { it.bounds }.eachCount()
/** Converts a list of IconPoint into a map of the count of different icon.coord */
private fun iconsToPosCountMap(widgets: List<IconPoint>) =
- widgets.groupingBy { it.getCoord() }.eachCount()
+ widgets.groupingBy { it.coord }.eachCount()
override fun compare(
cellLayoutBoard: CellLayoutBoard,
@@ -47,7 +47,7 @@
widgetsToBoundsMap(
otherCellLayoutBoard.widgets
.filter { !it.shouldIgnore() }
- .filter { !overlapsWithIgnored(ignoredRectangles, it.mBounds) }
+ .filter { !overlapsWithIgnored(ignoredRectangles, it.bounds) }
)
if (widgetsMap != otherWidgetMap) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
deleted file mode 100644
index 8a427dd..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.celllayout.board;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.ui.TestViewHelpers.findWidgetProvider;
-import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Process;
-import android.os.UserHandle;
-import android.util.Log;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-
-import java.util.function.Supplier;
-import java.util.stream.IntStream;
-
-public class TestWorkspaceBuilder {
-
- private static final String TAG = "CellLayoutBoardBuilder";
- private static final String TEST_ACTIVITY_PACKAGE_PREFIX = "com.android.launcher3.tests.";
- private ComponentName mAppComponentName = new ComponentName(
- "com.google.android.calculator", "com.android.calculator2.Calculator");
- private UserHandle mMyUser;
-
- private Context mContext;
-
- public TestWorkspaceBuilder(Context context) {
- mMyUser = Process.myUserHandle();
- mContext = context;
- }
-
- /**
- * Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases.
- */
- private FavoriteItemsTransaction fillWithWidgets(WidgetRect widgetRect,
- FavoriteItemsTransaction transaction, int screenId) {
- int initX = widgetRect.getCellX();
- int initY = widgetRect.getCellY();
- for (int x = initX; x < initX + widgetRect.getSpanX(); x++) {
- for (int y = initY; y < initY + widgetRect.getSpanY(); y++) {
- try {
- // this widgets are filling, we don't care if we can't place them
- transaction.addItem(createWidgetInCell(
- new WidgetRect(CellType.IGNORE,
- new Rect(x, y, x, y)), screenId));
- } catch (Exception e) {
- Log.d(TAG, "Unable to place filling widget at " + x + "," + y);
- }
- }
- }
- return transaction;
- }
-
- private AppInfo getApp() {
- return new AppInfo(mAppComponentName, "test icon", mMyUser,
- AppInfo.makeLaunchIntent(mAppComponentName));
- }
-
- /**
- * Helper to set the app to use for the test workspace,
- * using activity-alias from AndroidManifest-common.
- * @param testAppName the android:name field of the test app activity-alias to use
- */
- public void setTestAppActivityAlias(String testAppName) {
- this.mAppComponentName = new ComponentName(
- getInstrumentation().getContext().getPackageName(),
- TEST_ACTIVITY_PACKAGE_PREFIX + testAppName
- );
- }
-
- private void addCorrespondingWidgetRect(WidgetRect widgetRect,
- FavoriteItemsTransaction transaction, int screenId) {
- if (widgetRect.mType == 'x') {
- fillWithWidgets(widgetRect, transaction, screenId);
- } else {
- transaction.addItem(createWidgetInCell(widgetRect, screenId));
- }
- }
-
- /**
- * Builds the given board into the transaction
- */
- public FavoriteItemsTransaction buildFromBoard(CellLayoutBoard board,
- FavoriteItemsTransaction transaction, final int screenId) {
- board.getWidgets().forEach(
- (widgetRect) -> addCorrespondingWidgetRect(widgetRect, transaction, screenId));
- board.getIcons().forEach((iconPoint) ->
- transaction.addItem(() -> createIconInCell(iconPoint, screenId))
- );
- board.getFolders().forEach((folderPoint) ->
- transaction.addItem(() -> createFolderInCell(folderPoint, screenId))
- );
- return transaction;
- }
-
- /**
- * Fills the hotseat row with apps instead of suggestions, for this to work the workspace should
- * be clean otherwise this doesn't overrides the existing icons.
- */
- public FavoriteItemsTransaction fillHotseatIcons(FavoriteItemsTransaction transaction) {
- IntStream.range(0, InvariantDeviceProfile.INSTANCE.get(mContext).numDatabaseHotseatIcons)
- .forEach(i -> transaction.addItem(() -> getHotseatValues(i)));
- return transaction;
- }
-
- private Supplier<ItemInfo> createWidgetInCell(
- WidgetRect widgetRect, int screenId) {
- // Create the widget lazily since the appWidgetId can get lost during setup
- return () -> {
- LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
- LauncherAppWidgetInfo item = createWidgetInfo(info, getApplicationContext(), true);
- item.cellX = widgetRect.getCellX();
- item.cellY = widgetRect.getCellY();
- item.spanX = widgetRect.getSpanX();
- item.spanY = widgetRect.getSpanY();
- item.screenId = screenId;
- return item;
- };
- }
-
- public FolderInfo createFolderInCell(FolderPoint folderPoint, int screenId) {
- FolderInfo folderInfo = new FolderInfo();
- folderInfo.screenId = screenId;
- folderInfo.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
- folderInfo.cellX = folderPoint.coord.x;
- folderInfo.cellY = folderPoint.coord.y;
- folderInfo.minSpanY = folderInfo.minSpanX = folderInfo.spanX = folderInfo.spanY = 1;
- folderInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, null);
-
- for (int i = 0; i < folderPoint.getNumberIconsInside(); i++) {
- folderInfo.add(getDefaultWorkspaceItem(screenId), false);
- }
-
- return folderInfo;
- }
-
- private WorkspaceItemInfo getDefaultWorkspaceItem(int screenId) {
- WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
- item.screenId = screenId;
- item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
- item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
- return item;
- }
-
- private ItemInfo createIconInCell(IconPoint iconPoint, int screenId) {
- WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
- item.screenId = screenId;
- item.cellX = iconPoint.getCoord().x;
- item.cellY = iconPoint.getCoord().y;
- item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
- item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
- return item;
- }
-
- private ItemInfo getHotseatValues(int x) {
- WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
- item.cellX = x;
- item.cellY = 0;
- item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
- item.rank = x;
- item.screenId = x;
- item.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
- return item;
- }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt
new file mode 100644
index 0000000..8952b85
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.kt
@@ -0,0 +1,191 @@
+/*
+ * 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.celllayout.board
+
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.Rect
+import android.os.Process
+import android.os.UserHandle
+import android.util.Log
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.celllayout.FavoriteItemsTransaction
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.ui.TestViewHelpers
+import com.android.launcher3.util.WidgetUtils
+import java.util.function.Supplier
+
+class TestWorkspaceBuilder(private val mContext: Context) {
+
+ private var appComponentName =
+ ComponentName("com.google.android.calculator", "com.android.calculator2.Calculator")
+ private val myUser: UserHandle = Process.myUserHandle()
+
+ /** Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases. */
+ private fun fillWithWidgets(
+ widgetRect: WidgetRect,
+ transaction: FavoriteItemsTransaction,
+ screenId: Int
+ ): FavoriteItemsTransaction {
+ val initX = widgetRect.cellX
+ val initY = widgetRect.cellY
+ for (x in initX until initX + widgetRect.spanX) {
+ for (y in initY until initY + widgetRect.spanY) {
+ try {
+ // this widgets are filling, we don't care if we can't place them
+ transaction.addItem(
+ createWidgetInCell(WidgetRect(CellType.IGNORE, Rect(x, y, x, y)), screenId)
+ )
+ } catch (e: Exception) {
+ Log.d(TAG, "Unable to place filling widget at $x,$y")
+ }
+ }
+ }
+ return transaction
+ }
+
+ private fun app() =
+ AppInfo(appComponentName, "test icon", myUser, AppInfo.makeLaunchIntent(appComponentName))
+
+ /**
+ * Helper to set the app to use for the test workspace, using activity-alias from
+ * AndroidManifest-common.
+ *
+ * @param testAppName the android:name field of the test app activity-alias to use
+ */
+ fun setTestAppActivityAlias(testAppName: String) {
+ appComponentName =
+ ComponentName(
+ InstrumentationRegistry.getInstrumentation().context.packageName,
+ TEST_ACTIVITY_PACKAGE_PREFIX + testAppName
+ )
+ }
+
+ private fun addCorrespondingWidgetRect(
+ widgetRect: WidgetRect,
+ transaction: FavoriteItemsTransaction,
+ screenId: Int
+ ) {
+ if (widgetRect.type == 'x') {
+ fillWithWidgets(widgetRect, transaction, screenId)
+ } else {
+ transaction.addItem(createWidgetInCell(widgetRect, screenId))
+ }
+ }
+
+ /** Builds the given board into the transaction */
+ fun buildFromBoard(
+ board: CellLayoutBoard,
+ transaction: FavoriteItemsTransaction,
+ screenId: Int
+ ): FavoriteItemsTransaction {
+ board.widgets.forEach { addCorrespondingWidgetRect(it, transaction, screenId) }
+ board.icons.forEach { transaction.addItem { createIconInCell(it, screenId) } }
+ board.folders.forEach { transaction.addItem { createFolderInCell(it, screenId) } }
+ return transaction
+ }
+
+ /**
+ * Fills the hotseat row with apps instead of suggestions, for this to work the workspace should
+ * be clean otherwise this doesn't overrides the existing icons.
+ */
+ fun fillHotseatIcons(transaction: FavoriteItemsTransaction): FavoriteItemsTransaction {
+ for (i in 0..<InvariantDeviceProfile.INSTANCE[mContext].numDatabaseHotseatIcons) {
+ transaction.addItem { getHotseatValues(i) }
+ }
+ return transaction
+ }
+
+ private fun createWidgetInCell(widgetRect: WidgetRect, paramScreenId: Int): Supplier<ItemInfo> {
+ // Create the widget lazily since the appWidgetId can get lost during setup
+ return Supplier<ItemInfo> {
+ WidgetUtils.createWidgetInfo(
+ TestViewHelpers.findWidgetProvider(false),
+ ApplicationProvider.getApplicationContext(),
+ true
+ )
+ .apply {
+ cellX = widgetRect.cellX
+ cellY = widgetRect.cellY
+ spanX = widgetRect.spanX
+ spanY = widgetRect.spanY
+ screenId = paramScreenId
+ }
+ }
+ }
+
+ fun createFolderInCell(folderPoint: FolderPoint, paramScreenId: Int): FolderInfo =
+ FolderInfo().apply {
+ screenId = paramScreenId
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ cellX = folderPoint.coord.x
+ cellY = folderPoint.coord.y
+ spanY = 1
+ spanX = 1
+ minSpanX = 1
+ minSpanY = 1
+ setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, null)
+ for (i in 0 until folderPoint.numberIconsInside) {
+ add(getDefaultWorkspaceItem(paramScreenId), false)
+ }
+ }
+
+ private fun getDefaultWorkspaceItem(paramScreenId: Int): WorkspaceItemInfo =
+ WorkspaceItemInfo(app()).apply {
+ screenId = paramScreenId
+ spanY = 1
+ spanX = 1
+ minSpanX = 1
+ minSpanY = 1
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ }
+
+ private fun createIconInCell(iconPoint: IconPoint, paramScreenId: Int) =
+ WorkspaceItemInfo(app()).apply {
+ screenId = paramScreenId
+ cellX = iconPoint.coord.x
+ cellY = iconPoint.coord.y
+ spanY = 1
+ spanX = 1
+ minSpanX = 1
+ minSpanY = 1
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ }
+
+ private fun getHotseatValues(x: Int) =
+ WorkspaceItemInfo(app()).apply {
+ cellX = x
+ cellY = 0
+ spanY = 1
+ spanX = 1
+ minSpanX = 1
+ minSpanY = 1
+ rank = x
+ screenId = x
+ container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
+ }
+
+ companion object {
+ private const val TAG = "CellLayoutBoardBuilder"
+ private const val TEST_ACTIVITY_PACKAGE_PREFIX = "com.android.launcher3.tests."
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java
deleted file mode 100644
index c90ce85..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.celllayout.board;
-
-import android.graphics.Rect;
-
-public class WidgetRect {
- public char mType;
- public Rect mBounds;
-
- public WidgetRect(char type, Rect bounds) {
- this.mType = type;
- this.mBounds = bounds;
- }
-
- public int getSpanX() {
- return mBounds.right - mBounds.left + 1;
- }
-
- public int getSpanY() {
- return mBounds.top - mBounds.bottom + 1;
- }
-
- public int getCellX() {
- return mBounds.left;
- }
-
- public int getCellY() {
- return mBounds.bottom;
- }
-
- boolean shouldIgnore() {
- return this.mType == CellType.IGNORE;
- }
-
- boolean contains(int x, int y) {
- return mBounds.contains(x, y);
- }
-
- @Override
- public String toString() {
- return "WidgetRect type = " + mType + " x = " + getCellX() + " | y " + getCellY()
- + " xs = " + getSpanX() + " ys = " + getSpanY();
- }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt
new file mode 100644
index 0000000..e27926f
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheUpdateHandlerTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.icons
+
+import android.content.ComponentName
+import android.content.pm.PackageInfo
+import android.database.Cursor
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.icons.cache.BaseIconCache
+import com.android.launcher3.icons.cache.CachingLogic
+import com.android.launcher3.icons.cache.IconCacheUpdateHandler
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.doReturn
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconCacheUpdateHandlerTest {
+
+ @Mock private lateinit var cursor: Cursor
+ @Mock private lateinit var user: UserHandle
+ @Mock private lateinit var cachingLogic: CachingLogic<String>
+ @Mock private lateinit var baseIconCache: BaseIconCache
+
+ private var componentMap: HashMap<ComponentName, String> = hashMapOf()
+ private var ignorePackages: Set<String> = setOf()
+ private var packageInfoMap: HashMap<String, PackageInfo> = hashMapOf()
+
+ private val dummyRowData =
+ IconCacheRowData(
+ "com.android.fake/.FakeActivity",
+ System.currentTimeMillis(),
+ 1,
+ 1.0.toLong(),
+ "stateOfConfusion"
+ )
+
+ @Before
+ fun setup() {
+
+ MockitoAnnotations.initMocks(this)
+ // Load in a specific row to the database
+ doReturn(0).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_COMPONENT)
+ doReturn(1).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_LAST_UPDATED)
+ doReturn(2).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_VERSION)
+ doReturn(3).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_ROWID)
+ doReturn(4).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_SYSTEM_STATE)
+ doReturn(dummyRowData.component).`when`(cursor).getString(0)
+ doReturn(dummyRowData.lastUpdated).`when`(cursor).getLong(1)
+ doReturn(dummyRowData.version).`when`(cursor).getInt(2)
+ doReturn(dummyRowData.row).`when`(cursor).getLong(3)
+ doReturn(dummyRowData.systemState).`when`(cursor).getString(4)
+ }
+
+ @Test
+ fun `IconCacheUpdateHandler returns null if the component name is malformed`() {
+ val updateHandlerUnderTest = IconCacheUpdateHandler(packageInfoMap, baseIconCache)
+
+ val result =
+ updateHandlerUnderTest.updateOrDeleteIcon(
+ cursor,
+ componentMap,
+ ignorePackages,
+ user,
+ cachingLogic
+ )
+
+ assert(result == null)
+ }
+}
+
+data class IconCacheRowData(
+ val component: String,
+ val lastUpdated: Long,
+ val version: Int,
+ val row: Long,
+ val systemState: String
+)
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
index 71f7d47..ff545fe 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WidgetsModelTest.kt
@@ -186,6 +186,35 @@
assertThat(underTest.widgetsByComponentKey).isEmpty()
}
+ @Test
+ fun getWidgetsByPackageItem_returnsACopyOfMap() {
+ loadWidgets()
+
+ val latch = CountDownLatch(1)
+ Executors.MODEL_EXECUTOR.execute {
+ var update = true
+
+ // each "widgetsByPackageItem" read returns a different copy of the map held internally.
+ // Modifying one shouldn't impact another.
+ for ((_, _) in underTest.widgetsByPackageItem.entries) {
+ underTest.widgetsByPackageItem.clear()
+ if (update) { // trigger update
+ update = false
+ // Similarly, model could update its code independently while a client is
+ // iterating on the list.
+ underTest.update(app, /* packageUser= */ null)
+ }
+ }
+
+ latch.countDown()
+ }
+ if (!latch.await(LOAD_WIDGETS_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for test")
+ }
+
+ // No exception
+ }
+
private fun loadWidgets() {
val latch = CountDownLatch(1)
Executors.MODEL_EXECUTOR.execute {
diff --git a/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt b/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt
deleted file mode 100644
index 8204313..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPoolTest.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.recyclerview
-
-import android.content.Context
-import android.view.View
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.launcher3.util.Executors
-import com.android.launcher3.views.ActivityContext
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class AllAppsRecyclerViewPoolTest<T> where T : Context, T : ActivityContext {
-
- private lateinit var underTest: AllAppsRecyclerViewPool<T>
- private lateinit var adapter: RecyclerView.Adapter<*>
-
- @Mock private lateinit var parent: ViewGroup
- @Mock private lateinit var itemView: View
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- underTest = spy(AllAppsRecyclerViewPool())
- adapter =
- object : RecyclerView.Adapter<ViewHolder>() {
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
- object : ViewHolder(itemView) {}
-
- override fun getItemCount() = 0
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {}
- }
- underTest.setMaxRecycledViews(VIEW_TYPE, 20)
- }
-
- @Test
- fun preinflate_success() {
- underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 10 }
-
- awaitTasksCompleted()
- assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(10)
- }
-
- @Test
- fun preinflate_not_triggered() {
- underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 0 }
-
- awaitTasksCompleted()
- assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
- }
-
- @Test
- fun preinflate_cancel_before_runOnMainThread() {
- underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 10 }
- assertThat(underTest.mCancellableTask!!.canceled).isFalse()
-
- underTest.clear()
-
- awaitTasksCompleted()
- verify(underTest, never()).putRecycledView(any(ViewHolder::class.java))
- assertThat(underTest.mCancellableTask!!.canceled).isTrue()
- assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
- }
-
- @Test
- fun preinflate_cancel_after_run() {
- underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent) { 10 }
- assertThat(underTest.mCancellableTask!!.canceled).isFalse()
- awaitTasksCompleted()
-
- underTest.clear()
-
- verify(underTest, times(10)).putRecycledView(any(ViewHolder::class.java))
- assertThat(underTest.mCancellableTask!!.canceled).isTrue()
- assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
- }
-
- private fun awaitTasksCompleted() {
- Executors.VIEW_PREINFLATION_EXECUTOR.submit<Any> { null }.get()
- Executors.MAIN_EXECUTOR.submit<Any> { null }.get()
- }
-
- companion object {
- private const val VIEW_TYPE: Int = 4
- }
-}
diff --git a/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
similarity index 100%
rename from tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
rename to tests/multivalentTests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index a1f2d50..aa7f388 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -26,7 +26,7 @@
import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT;
import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT_SMALL;
-import static com.android.launcher3.Flags.FLAG_ENABLE_NEW_ARCHIVING_ICON;
+import static com.android.launcher3.Flags.FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS;
import static com.android.launcher3.LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
@@ -416,13 +416,14 @@
assertThat(mBubbleTextView.getIcon().hasBadge()).isEqualTo(false);
}
- @EnableFlags(FLAG_ENABLE_NEW_ARCHIVING_ICON)
+ @EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
@Test
public void applyIconAndLabel_setsImageSpan_whenInactiveArchivedApp() {
// Given
BubbleTextView spyTextView = spy(mBubbleTextView);
mGmailAppInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
BubbleTextView expectedTextView = new BubbleTextView(mContext);
+ mContext.getResources().getConfiguration().fontWeightAdjustment = 0;
int expectedDrawableId = mContext.getResources().getIdentifier(
"cloud_download_24px", /* name */
"drawable", /* defType */
@@ -451,7 +452,7 @@
assertThat(actualSpan.getVerticalAlignment()).isEqualTo(ALIGN_CENTER);
}
- @EnableFlags(FLAG_ENABLE_NEW_ARCHIVING_ICON)
+ @EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
public void applyIconAndLabel_setsBoldDrawable_whenBoldedTextForArchivedApp() {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt b/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt
new file mode 100644
index 0000000..39e1ec5
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import com.android.launcher3.util.coroutines.DispatcherProvider
+import kotlinx.coroutines.CoroutineDispatcher
+
+class TestDispatcherProvider(testDispatcher: CoroutineDispatcher) : DispatcherProvider {
+ override val default: CoroutineDispatcher = testDispatcher
+ override val io: CoroutineDispatcher = testDispatcher
+ override val main: CoroutineDispatcher = testDispatcher
+ override val unconfined: CoroutineDispatcher = testDispatcher
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/LauncherAppWidgetHostTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/LauncherAppWidgetHostTest.kt
new file mode 100644
index 0000000..79b493a
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/LauncherAppWidgetHostTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.Executors
+import java.util.function.IntConsumer
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertSame
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LauncherAppWidgetHostTest {
+
+ @Mock private lateinit var onAppWidgetRemovedCallback: IntConsumer
+
+ private val context = ActivityContextWrapper(getInstrumentation().targetContext)
+ private lateinit var underTest: LauncherAppWidgetHost
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ underTest = LauncherAppWidgetHost(context, onAppWidgetRemovedCallback, emptyList())
+ }
+
+ @Test
+ fun `Host set view to recycle`() {
+ val mockRecycleView = mock(ListenableHostView::class.java)
+
+ assertNull(underTest.viewToRecycle)
+ underTest.recycleViewForNextCreation(mockRecycleView)
+
+ assertSame(mockRecycleView, underTest.viewToRecycle)
+ }
+
+ @Test
+ fun `Host create view`() {
+ val mockRecycleView = mock(ListenableHostView::class.java)
+
+ var resultView = underTest.onCreateView(context, WIDGET_ID, null)
+
+ assertNotSame(mockRecycleView, resultView)
+
+ underTest.recycleViewForNextCreation(mockRecycleView)
+ resultView = underTest.onCreateView(context, WIDGET_ID, null)
+
+ assertSame(mockRecycleView, resultView)
+ }
+
+ @Test
+ fun `Runnable called when app widget removed`() {
+ underTest.onAppWidgetRemoved(WIDGET_ID)
+
+ Executors.MODEL_EXECUTOR.submit {}.get()
+ getInstrumentation().waitForIdleSync()
+
+ verify(onAppWidgetRemovedCallback).accept(WIDGET_ID)
+ }
+
+ companion object {
+ const val WIDGET_ID = 10001
+ }
+}
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 5516f45..7c9f99a 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -25,16 +25,23 @@
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
import com.android.launcher3.LauncherPrefs.Companion.get
+import com.android.launcher3.graphics.PreloadIconDrawable
import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.FastBitmapDrawable
import com.android.launcher3.icons.UserBadgeDrawable
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED
+import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE
+import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.Executors
import com.android.launcher3.util.FlagOp
import com.android.launcher3.util.LauncherLayoutBuilder
import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.TestUtil
import com.android.launcher3.util.UserIconInfo
+import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -219,6 +226,39 @@
)
}
+ @Test
+ fun `Inactive archived app previews are not drawn as preload icon`() {
+ // Given
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+ val archivedApp =
+ WorkspaceItemInfo().apply {
+ runtimeStatusFlags = runtimeStatusFlags or FLAG_ARCHIVED
+ runtimeStatusFlags = runtimeStatusFlags and FLAG_INSTALL_SESSION_ACTIVE.inv()
+ }
+ // When
+ previewItemManager.setDrawable(drawingParams, archivedApp)
+ // Then
+ assertThat(drawingParams.drawable).isNotInstanceOf(PreloadIconDrawable::class.java)
+ }
+
+ @Test
+ fun `Actively installing archived app previews are drawn as preload icon`() {
+ // Given
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+ val archivedApp =
+ WorkspaceItemInfo().apply {
+ runtimeStatusFlags = runtimeStatusFlags or FLAG_ARCHIVED
+ runtimeStatusFlags = runtimeStatusFlags or FLAG_INSTALL_SESSION_ACTIVE
+ }
+ // When
+ TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) {
+ // Run on main thread because preload drawable triggers animator
+ previewItemManager.setDrawable(drawingParams, archivedApp)
+ }
+ // Then
+ assertThat(drawingParams.drawable).isInstanceOf(PreloadIconDrawable::class.java)
+ }
+
private fun profileFlagOp(type: Int) =
UserIconInfo(Process.myUserHandle(), type).applyBitmapInfoFlags(FlagOp.NO_OP)
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index c926ba9..749a75a 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
import static com.android.launcher3.testing.shared.TestProtocol.WIDGET_CONFIG_NULL_EXTRA_INTENT;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -44,6 +43,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.rule.LimitDevicesRule;
import android.system.OsConstants;
import android.util.Log;
@@ -64,7 +64,6 @@
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
@@ -224,6 +223,9 @@
@Rule
public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
+ @Rule
+ public LimitDevicesRule mlimitDevicesRule = new LimitDevicesRule();
+
public static void initialize(AbstractLauncherUiTest test) throws Exception {
test.reinitializeLauncherData();
test.mDevice.pressHome();
@@ -237,16 +239,12 @@
}
protected void clearPackageData(String pkg) throws IOException, InterruptedException {
- final CountDownLatch count = new CountDownLatch(2);
- final SimpleBroadcastReceiver broadcastReceiver =
- new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> count.countDown());
- // We OK to make binder calls on main thread in test.
- broadcastReceiver.registerPkgActions(mTargetContext, pkg,
- Intent.ACTION_PACKAGE_RESTARTED, Intent.ACTION_PACKAGE_DATA_CLEARED);
-
- mDevice.executeShellCommand("pm clear " + pkg);
- assertTrue(pkg + " didn't restart", count.await(20, TimeUnit.SECONDS));
- mTargetContext.unregisterReceiver(broadcastReceiver);
+ assertTrue("pm clear command failed",
+ mDevice.executeShellCommand("pm clear " + pkg)
+ .contains("Success"));
+ assertTrue("pm wait-for-handler command failed",
+ mDevice.executeShellCommand("pm wait-for-handler")
+ .contains("Success"));
}
protected TestRule getRulesInsideActivityMonitor() {
diff --git a/tests/src/com/android/launcher3/ui/DoubleShadowIconDrawableTest.kt b/tests/src/com/android/launcher3/ui/DoubleShadowIconDrawableTest.kt
new file mode 100644
index 0000000..1cee71c
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/DoubleShadowIconDrawableTest.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.ui
+
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.views.DoubleShadowIconDrawable
+import com.android.launcher3.views.ShadowInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DoubleShadowIconDrawableTest {
+
+ @Test
+ fun `DoubleShadowIconDrawable is setup correctly from given ShadowInfo`() {
+ // Given
+ val shadowInfo: ShadowInfo = mock()
+ val originalDrawable: Drawable = mock()
+ val iconSize = 2
+ val iconInsetSize = 1
+ // When
+ val drawableUnderTest =
+ DoubleShadowIconDrawable(shadowInfo, originalDrawable, iconSize, iconInsetSize)
+ // Then
+ assertThat(drawableUnderTest.intrinsicHeight).isEqualTo(iconSize)
+ assertThat(drawableUnderTest.intrinsicWidth).isEqualTo(iconSize)
+ }
+
+ @Test
+ fun `createShadowRenderNode creates RenderNode for shadow effects`() {
+ // Given
+ val shadowInfo =
+ ShadowInfo(
+ ambientShadowBlur = 1f,
+ ambientShadowColor = 2,
+ keyShadowBlur = 3f,
+ keyShadowOffsetX = 4f,
+ keyShadowOffsetY = 5f,
+ keyShadowColor = 6
+ )
+ val originalDrawable: Drawable = mock()
+ val iconSize = 2
+ val iconInsetSize = 1
+ // When
+ val shadowDrawableUnderTest =
+ spy(DoubleShadowIconDrawable(shadowInfo, originalDrawable, iconSize, iconInsetSize))
+ shadowDrawableUnderTest.createShadowRenderNode()
+ // Then
+ verify(shadowDrawableUnderTest)
+ .createShadowRenderEffect(
+ shadowInfo.ambientShadowBlur,
+ 0f,
+ 0f,
+ Color.alpha(shadowInfo.ambientShadowColor).toFloat()
+ )
+ verify(shadowDrawableUnderTest)
+ .createShadowRenderEffect(
+ shadowInfo.keyShadowBlur,
+ shadowInfo.keyShadowOffsetX,
+ shadowInfo.keyShadowOffsetY,
+ Color.alpha(shadowInfo.keyShadowColor).toFloat()
+ )
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/ShadowInfoTest.kt b/tests/src/com/android/launcher3/ui/ShadowInfoTest.kt
new file mode 100644
index 0000000..ef4dc1a
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/ShadowInfoTest.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.ui
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.util.AttributeSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.R
+import com.android.launcher3.views.ShadowInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShadowInfoTest {
+
+ @Test
+ fun `ShadowInfo is created correctly from context`() {
+ // Given
+ val mockContext: Context = mock()
+ val mockAttrs: AttributeSet = mock()
+ val styledAttrs: TypedArray = mock()
+ val expectedShadowInfo =
+ ShadowInfo(
+ ambientShadowBlur = 1f,
+ ambientShadowColor = 2,
+ keyShadowBlur = 3f,
+ keyShadowOffsetX = 4f,
+ keyShadowOffsetY = 5f,
+ keyShadowColor = 6
+ )
+ doReturn(styledAttrs)
+ .whenever(mockContext)
+ .obtainStyledAttributes(mockAttrs, R.styleable.ShadowInfo, 0, 0)
+ doReturn(1)
+ .whenever(styledAttrs)
+ .getDimensionPixelSize(R.styleable.ShadowInfo_ambientShadowBlur, 0)
+ doReturn(2).whenever(styledAttrs).getColor(R.styleable.ShadowInfo_ambientShadowColor, 0)
+ doReturn(3)
+ .whenever(styledAttrs)
+ .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowBlur, 0)
+ doReturn(4)
+ .whenever(styledAttrs)
+ .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetX, 0)
+ doReturn(5)
+ .whenever(styledAttrs)
+ .getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetY, 0)
+ doReturn(6).whenever(styledAttrs).getColor(R.styleable.ShadowInfo_keyShadowColor, 0)
+ // When
+ val actualShadowInfo = ShadowInfo.fromContext(mockContext, mockAttrs, 0)
+ // Then
+ assertThat(actualShadowInfo.ambientShadowBlur).isEqualTo(1)
+ assertThat(actualShadowInfo.ambientShadowColor).isEqualTo(2)
+ assertThat(actualShadowInfo.keyShadowBlur).isEqualTo(3)
+ assertThat(actualShadowInfo.keyShadowOffsetX).isEqualTo(4)
+ assertThat(actualShadowInfo.keyShadowOffsetY).isEqualTo(5)
+ assertThat(actualShadowInfo.keyShadowColor).isEqualTo(6)
+ assertThat(actualShadowInfo).isEqualTo(expectedShadowInfo)
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 988aa94..b7ebfcd 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -16,7 +16,7 @@
package com.android.launcher3.tapl;
-import static com.android.launcher3.tapl.BaseOverview.TASK_RES_ID;
+import static com.android.launcher3.tapl.BaseOverview.TASK_SELECTOR;
import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
@@ -117,10 +117,10 @@
// non-tablet overview, snapshots can be on either side of the swiped
// task, but we still check that they become visible after swiping and
// pausing.
- mLauncher.waitForOverviewObject(TASK_RES_ID);
+ mLauncher.waitForObjectBySelector(TASK_SELECTOR);
if (mLauncher.isTablet()) {
List<UiObject2> tasks = mLauncher.getDevice().findObjects(
- mLauncher.getOverviewObjectSelector(TASK_RES_ID));
+ TASK_SELECTOR);
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
mLauncher.assertTrue(
"All tasks not to the left of the swiped task",
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 567a8bd..e71b49f 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -19,7 +19,9 @@
import static android.view.KeyEvent.KEYCODE_ESCAPE;
import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
+import static com.android.launcher3.tapl.LauncherInstrumentation.log;
import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
+import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import android.graphics.Rect;
@@ -35,9 +37,11 @@
import com.android.launcher3.testing.shared.TestProtocol;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -46,7 +50,9 @@
*/
public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
private static final String TAG = "BaseOverview";
- protected static final String TASK_RES_ID = "task";
+ protected static final BySelector TASK_SELECTOR = By.res(Pattern.compile(
+ getOverviewPackageName()
+ + ":id/(task_view_single|task_view_grouped|task_view_desktop)"));
private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
private static final Pattern EVENT_ENTER_DOWN = Pattern.compile(
@@ -56,10 +62,22 @@
private static final int FLINGS_FOR_DISMISS_LIMIT = 40;
+ private final @Nullable UiObject2 mLiveTileTask;
+
+
BaseOverview(LauncherInstrumentation launcher) {
+ this(launcher, /*launchedFromApp=*/false);
+ }
+
+ BaseOverview(LauncherInstrumentation launcher, boolean launchedFromApp) {
super(launcher);
verifyActiveContainer();
verifyActionsViewVisibility();
+ if (launchedFromApp) {
+ mLiveTileTask = getCurrentTaskUnchecked();
+ } else {
+ mLiveTileTask = null;
+ }
}
@Override
@@ -79,7 +97,7 @@
private void flingForwardImpl() {
try (LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to fling forward in overview")) {
- LauncherInstrumentation.log("Overview.flingForward before fling");
+ log("Overview.flingForward before fling");
final UiObject2 overview = verifyActiveContainer();
final int leftMargin =
mLauncher.getTargetInsets().left + mLauncher.getEdgeSensitivityWidth();
@@ -105,7 +123,7 @@
private void flingBackwardImpl() {
try (LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to fling backward in overview")) {
- LauncherInstrumentation.log("Overview.flingBackward before fling");
+ log("Overview.flingBackward before fling");
final UiObject2 overview = verifyActiveContainer();
final int rightMargin =
mLauncher.getTargetInsets().right + mLauncher.getEdgeSensitivityWidth();
@@ -276,37 +294,56 @@
*/
@NonNull
public OverviewTask getCurrentTask() {
+ UiObject2 currentTask = getCurrentTaskUnchecked();
+ mLauncher.assertNotNull("Unable to find a task", currentTask);
+ return new OverviewTask(mLauncher, currentTask, this);
+ }
+
+ @Nullable
+ private UiObject2 getCurrentTaskUnchecked() {
final List<UiObject2> taskViews = getTasks();
- mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
+ if (taskViews.isEmpty()) {
+ return null;
+ }
// The widest, and most top-right task should be the current task
- UiObject2 currentTask = Collections.max(taskViews,
+ return Collections.max(taskViews,
Comparator.comparingInt((UiObject2 t) -> t.getVisibleBounds().width())
.thenComparingInt((UiObject2 t) -> t.getVisibleCenter().x)
.thenComparing(Comparator.comparing(
(UiObject2 t) -> t.getVisibleCenter().y).reversed()));
- return new OverviewTask(mLauncher, currentTask, this);
}
- /** Returns an overview task matching TestActivity {@param activityNumber}. */
+ /**
+ * Returns an overview task that contains the specified test activity in its thumbnails.
+ *
+ * @param activityIndex index of TestActivity to match against
+ */
@NonNull
- public OverviewTask getTestActivityTask(int activityNumber) {
+ public OverviewTask getTestActivityTask(int activityIndex) {
+ return getTestActivityTask(Collections.singleton(activityIndex));
+ }
+
+ /**
+ * Returns an overview task that contains all the specified test activities in its thumbnails.
+ *
+ * @param activityNumbers collection of indices of TestActivity to match against
+ */
+ @NonNull
+ public OverviewTask getTestActivityTask(Collection<Integer> activityNumbers) {
final List<UiObject2> taskViews = getTasks();
mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
- final String activityName = "TestActivity" + activityNumber;
- UiObject2 task = null;
- for (UiObject2 taskView : taskViews) {
- // TODO(b/239452415): Use equals instead of descEndsWith
- if (taskView.getParent().hasObject(By.descEndsWith(activityName))) {
- task = taskView;
- break;
- }
- }
- mLauncher.assertNotNull(
- "Unable to find a task with " + activityName + " from the task list", task);
+ Optional<UiObject2> task = taskViews.stream().filter(
+ taskView -> activityNumbers.stream().allMatch(activityNumber ->
+ // TODO(b/239452415): Use equals instead of descEndsWith
+ taskView.hasObject(By.descEndsWith("TestActivity" + activityNumber))
+ )).findFirst();
- return new OverviewTask(mLauncher, task, this);
+ mLauncher.assertTrue("Unable to find a task with test activities " + activityNumbers
+ + " from the task list", task.isPresent());
+
+ return new OverviewTask(mLauncher, task.get(), this);
}
/**
@@ -328,8 +365,7 @@
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get overview tasks")) {
verifyActiveContainer();
- return mLauncher.getDevice().findObjects(
- mLauncher.getOverviewObjectSelector(TASK_RES_ID));
+ return mLauncher.getDevice().findObjects(TASK_SELECTOR);
}
}
@@ -506,4 +542,10 @@
}
return null;
}
+
+ protected boolean isLiveTile(UiObject2 task) {
+ // UiObject2.equals returns false even when mLiveTileTask and task have the same node, hence
+ // compare only hashCode as a workaround.
+ return mLiveTileTask != null && mLiveTileTask.hashCode() == task.hashCode();
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 200f2ff..b3ad930 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -33,6 +33,7 @@
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import androidx.annotation.NonNull;
import androidx.test.uiautomator.Condition;
import androidx.test.uiautomator.UiDevice;
@@ -75,6 +76,20 @@
return false;
}
+ @NonNull
+ @Override
+ public BaseOverview switchToOverview() {
+ try (LauncherInstrumentation.Closable ignored = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable ignored1 = mLauncher.addContextLayer(
+ "want to switch from background to overview")) {
+ verifyActiveContainer();
+ goToOverviewUnchecked();
+ return mLauncher.is3PLauncher()
+ ? new BaseOverview(mLauncher, /*launchedFromApp=*/true)
+ : new Overview(mLauncher, /*launchedFromApp=*/true);
+ }
+ }
+
/**
* Returns the taskbar.
*
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 75c1b24..a874062 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1585,7 +1585,7 @@
return objects;
}
- private UiObject2 waitForObjectBySelector(BySelector selector) {
+ UiObject2 waitForObjectBySelector(BySelector selector) {
Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
"LauncherInstrumentation.waitForObjectBySelector");
final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 50c2136..deb27e4 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -22,9 +22,12 @@
* Overview pane.
*/
public class Overview extends BaseOverview {
-
Overview(LauncherInstrumentation launcher) {
- super(launcher);
+ this(launcher, /*launchedFromApp=*/false);
+ }
+
+ Overview(LauncherInstrumentation launcher, boolean launchedFromApp) {
+ super(launcher, launchedFromApp);
}
@Override
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 6f420af..7a8ab49 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -40,16 +40,23 @@
public final class OverviewTask {
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
static final Pattern TASK_START_EVENT = Pattern.compile("startActivityFromRecentsAsync");
+ static final Pattern TASK_START_EVENT_DESKTOP = Pattern.compile("launchDesktopFromRecents");
+ static final Pattern TASK_START_EVENT_LIVE_TILE = Pattern.compile(
+ "composeRecentsLaunchAnimator");
static final Pattern SPLIT_SELECT_EVENT = Pattern.compile("enterSplitSelect");
static final Pattern SPLIT_START_EVENT = Pattern.compile("launchSplitTasks");
private final LauncherInstrumentation mLauncher;
+ @NonNull
private final UiObject2 mTask;
+ private final TaskViewType mType;
private final BaseOverview mOverview;
- OverviewTask(LauncherInstrumentation launcher, UiObject2 task, BaseOverview overview) {
+ OverviewTask(LauncherInstrumentation launcher, @NonNull UiObject2 task, BaseOverview overview) {
mLauncher = launcher;
+ mLauncher.assertNotNull("task must not be null", task);
mTask = task;
mOverview = overview;
+ mType = getType();
verifyActiveContainer();
}
@@ -220,7 +227,22 @@
return new LaunchedAppState(mLauncher);
}
} else {
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
+ final Pattern event;
+ if (mOverview.isLiveTile(mTask)) {
+ event = TASK_START_EVENT_LIVE_TILE;
+ } else if (mType == TaskViewType.DESKTOP) {
+ event = TASK_START_EVENT_DESKTOP;
+ } else {
+ event = TASK_START_EVENT;
+ }
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, event);
+
+ if (mType == TaskViewType.DESKTOP) {
+ try (LauncherInstrumentation.Closable ignored = mLauncher.addContextLayer(
+ "launched desktop")) {
+ mLauncher.waitForSystemUiObject("desktop_mode_caption");
+ }
+ }
return new LaunchedAppState(mLauncher);
}
}
@@ -273,6 +295,17 @@
return actual.contains(expected);
}
+ private TaskViewType getType() {
+ String resourceName = mTask.getResourceName();
+ if (resourceName.endsWith("task_view_grouped")) {
+ return TaskViewType.GROUPED;
+ } else if (resourceName.endsWith("task_view_desktop")) {
+ return TaskViewType.DESKTOP;
+ } else {
+ return TaskViewType.SINGLE;
+ }
+ }
+
/**
* Enum used to specify which task is retrieved when it is a split task.
*/
@@ -292,4 +325,10 @@
this.iconAppRes = iconAppRes;
}
}
+
+ private enum TaskViewType {
+ SINGLE,
+ GROUPED,
+ DESKTOP
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 902ad5b..90d32f3 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -97,6 +97,29 @@
}
}
+ /**
+ * Taps the Desktop item from the overview task menu and returns the LaunchedAppState
+ * representing the Desktop.
+ */
+ @NonNull
+ public LaunchedAppState tapDesktopMenuItem() {
+ try (LauncherInstrumentation.Closable ignored = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable ignored1 = mLauncher.addContextLayer(
+ "before tapping the desktop menu item")) {
+ mLauncher.executeAndWaitForLauncherStop(
+ () -> mLauncher.clickLauncherObject(
+ mLauncher.findObjectInContainer(mMenu, By.text("Desktop"))),
+ "tapped desktop menu item");
+
+ try (LauncherInstrumentation.Closable ignored2 = mLauncher.addContextLayer(
+ "tapped desktop menu item")) {
+ mLauncher.waitUntilSystemLauncherObjectGone("overview_panel");
+ mLauncher.waitForSystemUiObject("desktop_mode_caption");
+ return new LaunchedAppState(mLauncher);
+ }
+ }
+ }
+
/** Returns true if an item matching the given string is present in the menu. */
public boolean hasMenuItem(String expectedMenuItemText) {
UiObject2 menuItem = mLauncher.findObjectInContainer(mMenu, By.text(expectedMenuItemText));
@@ -104,14 +127,6 @@
}
/**
- * Returns the menu item specified by name if present.
- */
- public OverviewTaskMenuItem getMenuItemByName(String menuItemName) {
- return new OverviewTaskMenuItem(mLauncher,
- mLauncher.waitForObjectInContainer(mMenu, By.text(menuItemName)));
- }
-
- /**
* Taps outside task menu to dismiss it.
*/
public void touchOutsideTaskMenuToDismiss() {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java
deleted file mode 100644
index e3035bf..0000000
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.tapl;
-
-import android.graphics.Rect;
-
-import androidx.test.uiautomator.UiObject2;
-
-/** Represents an item in the overview task menu. */
-public class OverviewTaskMenuItem {
-
- private final LauncherInstrumentation mLauncher;
- private final UiObject2 mMenuItem;
-
- OverviewTaskMenuItem(LauncherInstrumentation launcher, UiObject2 menuItem) {
- mLauncher = launcher;
- mMenuItem = menuItem;
- }
-
- /**
- * Returns this menu item's visible bounds.
- */
- public Rect getVisibleBounds() {
- return mMenuItem.getVisibleBounds();
- }
-}