Merge "Revert "Add screen recording to TaplTestsQuickstep#testQuickSwitchToPreviousAppForTablet"" into main
diff --git a/Android.bp b/Android.bp
index ba04bb3..bcbd362 100644
--- a/Android.bp
+++ b/Android.bp
@@ -27,7 +27,7 @@
"android.os.flags-aconfig-java",
"android.appwidget.flags-aconfig-java",
"com.android.window.flags.window-aconfig-java",
- ]
+ ],
}
// Common source files used to build launcher (java and kotlin)
@@ -69,6 +69,15 @@
],
}
+// Source code for quickstep dagger
+filegroup {
+ name: "launcher-quickstep-dagger",
+ srcs: [
+ "quickstep/dagger/**/*.java",
+ "quickstep/dagger/**/*.kt",
+ ],
+}
+
// Source code for quickstep build with compose enabled, on top of launcher-src
filegroup {
name: "launcher-quickstep-compose-enabled-src",
@@ -153,7 +162,7 @@
soong_config_variables: {
release_enable_compose_in_launcher: {
srcs: [
- ":launcher-compose-enabled-src"
+ ":launcher-compose-enabled-src",
],
// Compose dependencies
@@ -166,7 +175,7 @@
// in compose/launcher3/facade/disabled/.
conditions_default: {
srcs: [
- ":launcher-compose-disabled-src"
+ ":launcher-compose-disabled-src",
],
static_libs: [],
},
@@ -179,7 +188,7 @@
soong_config_variables: {
release_enable_compose_in_launcher: {
srcs: [
- ":launcher-quickstep-compose-enabled-src"
+ ":launcher-quickstep-compose-enabled-src",
],
// Compose dependencies
@@ -192,7 +201,7 @@
// in compose/quickstep/facade/disabled/.
conditions_default: {
srcs: [
- ":launcher-quickstep-compose-disabled-src"
+ ":launcher-quickstep-compose-disabled-src",
],
static_libs: [],
},
@@ -221,7 +230,7 @@
android_library {
name: "launcher-aosp-tapl",
libs: [
- "framework-statsd",
+ "framework-statsd.stubs.module_lib",
],
static_libs: [
"androidx.annotation_annotation",
@@ -231,6 +240,7 @@
"androidx.preference_preference",
"SystemUISharedLib",
"//frameworks/libs/systemui:animationlib",
+ "//frameworks/libs/systemui:contextualeducationlib",
"launcher-testing-shared",
],
srcs: [
@@ -311,6 +321,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",
@@ -320,7 +331,9 @@
"kotlinx_coroutines",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
-
+ "dagger2",
+ "jsr330",
+ "com_android_systemui_shared_flags_lib",
],
manifest: "AndroidManifest-common.xml",
sdk_version: "current",
@@ -355,6 +368,7 @@
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
target_sdk_version: "current",
+ plugins: ["dagger2-compiler"],
privileged: true,
system_ext_specific: true,
@@ -383,13 +397,14 @@
"quickstep/res",
],
libs: [
- "framework-statsd",
+ "framework-statsd.stubs.module_lib",
],
static_libs: [
"Launcher3ResLib",
"lottie",
"SystemUISharedLib",
"SettingsLibSettingsTheme",
+ "dagger2",
],
manifest: "quickstep/AndroidManifest.xml",
min_sdk_version: "current",
@@ -405,6 +420,7 @@
srcs: [
":launcher-src",
":launcher-quickstep-src",
+ ":launcher-quickstep-dagger",
"go/quickstep/src/**/*.java",
"go/quickstep/src/**/*.kt",
],
@@ -419,7 +435,10 @@
"QuickstepResLib",
"androidx.room_room-runtime",
],
- plugins: ["androidx.room_room-compiler-plugin"],
+ plugins: [
+ "androidx.room_room-compiler-plugin",
+ "dagger2-compiler",
+ ],
manifest: "quickstep/AndroidManifest.xml",
additional_manifests: [
"go/AndroidManifest.xml",
@@ -435,16 +454,17 @@
name: "Launcher3QuickStepLib",
defaults: [
"launcher_compose_defaults",
- "quickstep_compose_defaults"
+ "quickstep_compose_defaults",
],
srcs: [
":launcher-src",
":launcher-quickstep-src",
+ ":launcher-quickstep-dagger",
":launcher-build-config",
],
resource_dirs: [],
libs: [
- "framework-statsd",
+ "framework-statsd.stubs.module_lib",
],
// Note the ordering here is important when it comes to resource
// overriding. We want the most specific resource overrides defined
@@ -456,6 +476,7 @@
],
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
+ plugins: ["dagger2-compiler"],
min_sdk_version: "current",
// TODO(b/319712088): re-enable use_resource_processor
use_resource_processor: false,
@@ -498,7 +519,6 @@
}
-
// Build rule for Launcher3 Go app with quickstep for Android Go devices.
// Note that the following two rules are exactly same, and should
// eventually be merged into a single target
@@ -538,6 +558,7 @@
include_filter: ["com.android.launcher3.*"],
},
}
+
android_app {
name: "Launcher3QuickStepGo",
static_libs: ["Launcher3GoLib"],
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 0df6c36..3769124 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -316,6 +316,7 @@
description: "Menu in Taskbar with options to launch and manage multiple instances of the same app"
bug: "355237285"
}
+
flag {
name: "navigate_to_child_preference"
namespace: "launcher"
@@ -332,3 +333,68 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "letter_fast_scroller"
+ namespace: "launcher"
+ description: "Change fast scroller to a lettered list"
+ bug: "358673724"
+}
+
+flag {
+ name: "enable_desktop_task_alpha_animation"
+ namespace: "launcher"
+ description: "Enables the animation of the desktop task's background view"
+ bug: "320307666"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "ignore_three_finger_trackpad_for_nav_handle_long_press"
+ namespace: "launcher"
+ description: "Ignore three finger trackpad event for nav handle long press"
+ bug: "342143522"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "one_grid_specs"
+ namespace: "launcher"
+ description: "Defines the new specs for grids based on OneGrid"
+ bug: "364711064"
+}
+
+flag {
+ name: "one_grid_mounted_mode"
+ namespace: "launcher"
+ description: "Support a fixed landscape mode for handheld devices"
+ bug: "364711735"
+}
+
+flag {
+ name: "one_grid_rotation_handling"
+ namespace: "launcher"
+ description: "New landscape approach for the workspace using different rows and columns in landscape and portrait"
+ bug: "364711814"
+}
+
+flag {
+ name: "grid_migration_refactor"
+ namespace: "launcher"
+ description: "Refactor grid migration such that the code is simpler to understand and update"
+ bug: "358399271"
+}
+
+flag {
+ name: "accessibility_scroll_on_allapps"
+ namespace: "launcher"
+ description: "Scroll to item position if accessibility focused"
+ bug: "265392261"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index 11740ee..23733a4 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -31,3 +31,20 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_large_desktop_windowing_tile"
+ namespace: "launcher_overview"
+ description: "Makes the desktop tiles larger and moves them to the front of the list in Overview."
+ bug: "353947137"
+}
+
+flag {
+ name: "enable_overview_command_helper_timeout"
+ namespace: "launcher_overview"
+ description: "Enables OverviewCommandHelper new version with a timeout to prevent the queue to be unresponsive."
+ bug: "351122926"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
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 1b9c661..2ef9f82 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -52,6 +52,7 @@
"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/quickstep/util/SplitScreenTestUtils.kt",
"tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java",
],
}
@@ -63,3 +64,11 @@
"tests/multivalentScreenshotTests/src/**/*.kt",
],
}
+
+filegroup {
+ name: "launcher3-quickstep-testing",
+ path: "testing",
+ srcs: [
+ "testing/**/*.kt",
+ ],
+}
diff --git a/quickstep/dagger/LauncherAppComponent.java b/quickstep/dagger/LauncherAppComponent.java
new file mode 100644
index 0000000..bd6008e
--- /dev/null
+++ b/quickstep/dagger/LauncherAppComponent.java
@@ -0,0 +1,35 @@
+/*
+ * 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.dagger;
+
+
+import com.android.quickstep.dagger.QuickStepModule;
+
+import dagger.Component;
+
+/**
+ * Root component for Dagger injection for Launcher Quickstep.
+ */
+@LauncherAppSingleton
+@Component(modules = QuickStepModule.class)
+public interface LauncherAppComponent extends LauncherBaseAppComponent {
+ /** Builder for quickstep LauncherAppComponent. */
+ @Component.Builder
+ interface Builder extends LauncherBaseAppComponent.Builder {
+ LauncherAppComponent build();
+ }
+}
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/drawable/keyboard_quick_switch_overview_button_background.xml b/quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
similarity index 78%
rename from quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
rename to quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
index 8180293..f204920 100644
--- a/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
+++ b/quickstep/res/drawable/keyboard_quick_switch_text_button_background.xml
@@ -15,8 +15,7 @@
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?attr/materialColorSurfaceBright" />
- <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+ <solid android:color="@android:color/white" />
+ <corners android:radius="@dimen/keyboard_quick_switch_text_button_radius" />
</shape>
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index 613edac..d1e5667 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -18,8 +18,8 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:importantForAccessibility="yes"
android:background="@drawable/keyboard_quick_switch_task_view_background"
android:clipToOutline="true"
@@ -27,8 +27,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -52,7 +52,7 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:visibility="gone"
- android:layout_marginStart="@dimen/keyboard_quick_switch_split_view_spacing"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_view_small_spacing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
new file mode 100644
index 0000000..0eccd8e
--- /dev/null
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:importantForAccessibility="yes"
+ android:background="@drawable/keyboard_quick_switch_task_view_background"
+ android:clipToOutline="true"
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/content"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_1"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_2"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:visibility="gone"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_view_small_spacing"
+
+ app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <ImageView
+ android:id="@+id/icon_1"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
+
+ <ImageView
+ android:id="@+id/icon_2"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:visibility="gone"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml
index 6a99a3b..0551c12 100644
--- a/quickstep/res/layout/digital_wellbeing_toast.xml
+++ b/quickstep/res/layout/digital_wellbeing_toast.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<TextView
+<com.android.quickstep.views.DigitalWellBeingToast
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
style="@style/TextTitle"
@@ -27,4 +27,5 @@
android:textColor="?attr/materialColorOnSecondaryFixed"
android:textSize="14sp"
android:autoSizeTextType="uniform"
- android:autoSizeMaxTextSize="14sp"/>
\ No newline at end of file
+ android:autoSizeMaxTextSize="14sp"
+ android:visibility="gone"/>
\ No newline at end of file
diff --git a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
similarity index 68%
rename from quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
rename to quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
index c76a2e3..c3f9e54 100644
--- a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
@@ -18,17 +18,20 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:clipToOutline="true"
android:importantForAccessibility="yes"
- launcher:focusBorderColor="?attr/materialColorOutline">
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+ launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/keyboard_quick_switch_overview_button_background"
+ android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:background="@drawable/keyboard_quick_switch_text_button_background"
+ android:backgroundTint="?androidprv:attr/materialColorSurfaceContainer"
+ android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -37,10 +40,11 @@
<ImageView
android:id="@+id/icon"
- android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_marginBottom="8dp"
- android:tint="?attr/materialColorOnSurface"
+ android:layout_width="@dimen/keyboard_quick_switch_desktop_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_desktop_icon_size"
+ android:layout_marginBottom="4dp"
+ android:tint="?androidprv:attr/materialColorOnSurface"
+ android:src="@drawable/ic_desktop"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
@@ -49,9 +53,9 @@
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
- style="@style/KeyboardQuickSwitchText"
+ style="@style/KeyboardQuickSwitchText.OnTaskView"
android:id="@+id/text"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
diff --git a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
similarity index 62%
copy from quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
copy to quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
index c76a2e3..0b44a2a 100644
--- a/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
+<!-- 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.
@@ -18,44 +18,47 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:clipToOutline="true"
android:importantForAccessibility="yes"
- launcher:focusBorderColor="?attr/materialColorOutline">
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+ launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/keyboard_quick_switch_overview_button_background"
+ android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:background="@drawable/keyboard_quick_switch_text_button_background"
+ android:backgroundTint="?androidprv:attr/materialColorSurfaceBright"
+ android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
- <ImageView
- android:id="@+id/icon"
- android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
- android:layout_marginBottom="8dp"
- android:tint="?attr/materialColorOnSurface"
-
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/text"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
-
<TextView
- style="@style/KeyboardQuickSwitchText"
- android:id="@+id/text"
+ style="@style/KeyboardQuickSwitchText.LargeText"
+ android:id="@+id/large_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
- app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/small_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <TextView
+ style="@style/KeyboardQuickSwitchText.OnTaskView"
+ android:id="@+id/small_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="center"
+
+ app:layout_constraintTop_toBottomOf="@id/large_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 8f09176..41eb623 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -18,8 +18,8 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
- android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:importantForAccessibility="yes"
android:background="@drawable/keyboard_quick_switch_task_view_background"
android:clipToOutline="true"
@@ -27,8 +27,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -52,7 +52,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
- android:layout_marginTop="@dimen/keyboard_quick_switch_split_view_spacing"
+ android:layout_marginTop="@dimen/keyboard_quick_switch_view_small_spacing"
app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
new file mode 100644
index 0000000..1474949
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:importantForAccessibility="yes"
+ android:background="@drawable/keyboard_quick_switch_task_view_background"
+ android:clipToOutline="true"
+ launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/content"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/thumbnail_2"/>
+
+ <include
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_2"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:layout_marginStart="@dimen/keyboard_quick_switch_view_small_spacing"
+
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <ImageView
+ android:id="@+id/icon_1"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
+
+ <ImageView
+ android:id="@+id/icon_2"
+ android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
+ android:importantForAccessibility="no"
+ android:visibility="gone"
+ android:scaleType="centerCrop"
+
+ app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 34193d3..760bcdb 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -47,4 +47,7 @@
android:inflatedId="@id/icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
+
+ <include layout="@layout/digital_wellbeing_toast"
+ android:id="@+id/digital_wellbeing_toast"/>
</com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 8c7090e..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_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 cb4b98f..c36a45e 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -73,4 +73,10 @@
android:inflatedId="@id/bottomRight_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
+
+ <include layout="@layout/digital_wellbeing_toast"
+ android:id="@+id/digital_wellbeing_toast"/>
+
+ <include layout="@layout/digital_wellbeing_toast"
+ android:id="@+id/bottomRight_digital_wellbeing_toast"/>
</com.android.quickstep.views.GroupedTaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
index 784a094..d90d916 100644
--- a/quickstep/res/layout/task_thumbnail.xml
+++ b/quickstep/res/layout/task_thumbnail.xml
@@ -15,22 +15,23 @@
-->
<com.android.quickstep.task.thumbnail.TaskThumbnailView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent" >
- <ImageView
+ <com.android.quickstep.views.FixedSizeImageView
android:id="@+id/task_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
android:scaleType="matrix"
- android:visibility="gone"/>
+ android:visibility="invisible"/>
<com.android.quickstep.task.thumbnail.LiveTileView
android:id="@+id/task_thumbnail_live_tile"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="gone"/>
+ android:visibility="invisible"/>
<View
android:id="@+id/task_thumbnail_scrim"
@@ -39,16 +40,23 @@
android:background="@color/overview_foreground_scrim_color"
android:alpha="0" />
- <FrameLayout
- android:id="@+id/splash_container"
+ <View
+ android:id="@+id/splash_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="gone">
- <ImageView
- android:id="@+id/splash_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:importantForAccessibility="no" />
- </FrameLayout>
+ android:background="@android:color/black"
+ android:alpha="0"
+ android:importantForAccessibility="no" />
+
+ <com.android.quickstep.views.FixedSizeImageView
+ android:id="@+id/splash_icon"
+ android:layout_width="@dimen/task_thumbnail_splash_icon_size"
+ android:layout_height="@dimen/task_thumbnail_splash_icon_size"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:scaleType="fitCenter"
+ android:alpha="0"
+ android:importantForAccessibility="no" />
</com.android.quickstep.task.thumbnail.TaskThumbnailView>
\ No newline at end of file
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index f8c8977..4122637 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Rekenaar"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Werkskerm"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Kanselleer"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taakbalkverdeler"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Wys nog # app.}other{Wys nog # apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Wys # rekenaarapp.}other{Wys # rekenaarapps.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{meer app}other{meer apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Werkskerm"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Borrel"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oorvloei"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index f5cef7b..956767ee 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ዴስክቶፕ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ዴስክቶፕ"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"የተግባር አሞሌ አካፋይ"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ወደ ላይ/ግራ ይውሰዱ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ወደ ታች/ቀኝ ይውሰዱ"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ተጨማሪ # መተግበሪያ አሳይ።}one{ተጨማሪ # መተግበሪያ አሳይ።}other{ተጨማሪ # መተግበሪያዎች አሳይ።}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# የዴስክቶፕ መተግበሪያ አሳይ።}one{# የዴስክቶፕ መተግበሪያ አሳይ።}other{# የዴስክቶፕ መተግበሪያዎች አሳይ።}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ተጨማሪ መተግበሪያ}one{ተጨማሪ መተግበሪያ}other{ተጨማሪ መተግበሪያዎች}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ዴስክቶፕ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"አረፋ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ትርፍ ፍሰት"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 52a18e9..e691663 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"شكل مجاني"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"الكمبيوتر المكتبي"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"كمبيوتر مكتبي"</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>
@@ -88,7 +89,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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"مقسِّم شريط التطبيقات"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{إظهار تطبيق واحد آخر}zero{إظهار # تطبيق آخر}two{إظهار تطبيقَين آخرَين}few{إظهار # تطبيقات أخرى}many{إظهار # تطبيقًا آخر}other{إظهار # تطبيق آخر}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{عرض تطبيق واحد متوافق مع الكمبيوتر المكتبي}zero{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}two{عرض تطبيقَين متوافقين مع الكمبيوتر المكتبي}few{عرض # تطبيقات متوافقة مع الكمبيوتر المكتبي}many{عرض # تطبيقًا متوافقًا مع الكمبيوتر المكتبي}other{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{تطبيق واحد آخر}zero{تطبيق آخر}two{تطبيقان آخران}few{تطبيقات أخرى}many{تطبيقًا آخر}other{تطبيق آخر}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"وضع الكمبيوتر المكتبي"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"فقاعة"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"القائمة الكاملة"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index d811543..912003b 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -22,6 +22,7 @@
<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_desktop" msgid="8081113562549637334">"ডেস্কটপ"</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 +100,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>
@@ -140,8 +141,8 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবাৰ বিভাজক"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আৰু # টা এপ্ দেখুৱাওক।}one{আৰু # টা এপ্ দেখুৱাওক।}other{আৰু # টা এপ্ দেখুৱাওক।}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# টা ডেস্কটপ এপ্ দেখুৱাওক।}one{# টা ডেস্কটপ এপ্ দেখুৱাওক।}other{# টা ডেস্কটপ এপ্ দেখুৱাওক।}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{অধিক এপ্}one{অধিক এপ্}other{অধিক এপ্}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"অ’ভাৰফ্ল’"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 3108ffe..b89b707 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Masaüstü"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Ləğv edin"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"İşləmə paneli ayırıcısı"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Daha # tətbiqi göstərin.}other{Daha # tətbiqi göstərin.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü tətbiqini göstərin.}other{# masaüstü tətbiqini göstərin.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{əlavə tətbiq}other{əlavə tətbiq}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Yumrucuq"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kənara çıxma"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index e6074b0..4ef487e 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Računar"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Računari"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -89,7 +90,7 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Gotovo!"</string>
<string name="allset_hint" msgid="459504134589971527">"Prevucite nagore da biste otvorili početni ekran"</string>
- <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da bisti išli na početni ekran"</string>
+ <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da biste otišli na početni ekran"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete da koristite <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Podešavanja kretanja kroz sistem"</annotation></string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Otkaži"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelnik trake zadataka"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računare.}one{Prikaži # aplikaciju za računare.}few{Prikaži # aplikacije za računare.}other{Prikaži # aplikacija za računare.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 5b871d4..c506acb 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Адвольная форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Працоўны стол"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Працоўны стол"</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>
@@ -39,7 +40,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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Раздзяляльнік панэлі задач"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Паказаць ячшэ # праграму.}one{Паказаць ячшэ # праграму.}few{Паказаць ячшэ # праграмы.}many{Паказаць ячшэ # праграм.}other{Паказаць ячшэ # праграмы.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Паказаць # праграму для ПК.}one{Паказаць # праграму для ПК.}few{Паказаць # праграмы для ПК.}many{Паказаць # праграм для ПК.}other{Паказаць # праграмы для ПК.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{даступная праграма}one{даступная праграма}few{даступныя праграмы}many{даступных праграм}other{даступнай праграмы}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Працоўны стол"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бурбалкі"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Меню з пашырэннем"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index dd87de8..d03e4f7 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Фиксиране"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Свободна форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"За компютър"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Настолен компютър"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделител на лентата на задачите"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показване на още # приложение.}other{Показване на още # приложения.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показване на # настолно приложение.}other{Показване на # настолни приложения.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{допълнително приложение}other{допълнителни приложения}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за настолни компютри"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Препълване"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 99a815f..0c568d9 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ফ্রি-ফর্ম"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ডেস্কটপ"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবার ডিভাইডার"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"উপরে/বাঁদিকে সরান"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"নিচে/ডানদিকে সরান"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আরও #টি অ্যাপ দেখুন।}one{আরও #টি অ্যাপ দেখুন।}other{আরও #টি অ্যাপ দেখুন।}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{#টি ডেস্কটপ অ্যাপ দেখুন।}one{#টি ডেস্কটপ অ্যাপ দেখুন।}other{#টি ডেস্কটপ অ্যাপ দেখুন।}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{আরও অ্যাপ}one{আরও অ্যাপ}other{আরও অ্যাপ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ওভারফ্লো"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 5f445ab..922883e 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodan oblik"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Radna površina"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Radna površina"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke korištenja aplikacije"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -47,7 +48,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Rotirajte uređaj"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Rotirajte uređaj da završite vodič za navigaciju pokretima"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prevucite s krajnjeg desnog ili krajnjeg lijevog ruba"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prevucite s krajnjeg desnog ili lijevog ruba"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Prevucite s desnog ili lijevog ruba prema sredini ekrana i pustite"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prevući zdesna da se vratite. Sljedeće naučite kako prebacivati između aplikacija."</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Savladali ste pokret za vraćanje. Sljedeće naučite kako prebacivati između aplikacija."</string>
@@ -73,7 +74,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Vodite računa da prevučete s donjeg ruba ekrana prema gore"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Pokušajte zadržati prozor duže prije puštanja"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Prevucite ravno nagore, a zatim zastanite"</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako koristiti pokrete. Idite u Postavke da isključite pokrete."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako koristiti pokrete. Da ih isključite, idite u Postavke."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Savladali ste pokret za prebacivanje između aplikacija"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prevucite da prebacujete između aplikacija"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Da se prebacujete između aplikacija, prevucite s dna ekrana nagore, zadržite, a zatim pustite."</string>
@@ -89,17 +90,17 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string>
<string name="allset_hint" msgid="459504134589971527">"Prevucite prema gore da odete na početni ekran"</string>
- <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete napočetni ekran"</string>
+ <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete na poč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">"Otkaži"</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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake zadataka"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore lijevo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje desno"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računar.}one{Prikaži # aplikaciju za računar.}few{Prikaži # aplikacije za računar.}other{Prikaži # aplikacija za računar.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni meni"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 2b8fadf..fe7933b 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"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>
@@ -59,7 +60,7 @@
<string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Per tornar a la pantalla anterior, llisca amb dos dits des de l\'extrem esquerre o dret cap al centre de la pantalla."</string>
<string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Torna enrere"</string>
<string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Llisca des de la vora esquerra o dreta cap al centre de la pantalla."</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla"</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla."</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Assegura\'t de no aturar-te abans de deixar anar."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Assegura\'t de lliscar recte cap amunt."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Has completat el gest per anar a la pantalla d\'inici. Ara, descobreix com pots tornar enrere."</string>
@@ -72,7 +73,7 @@
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Ben fet!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla."</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Prova de mantenir premuda la finestra durant més temps abans de deixar-la anar"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Assegura\'t de lliscar directament cap amunt i després aturar-te"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Assegura\'t de lliscar directament cap amunt i després aturar-te."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Has après a utilitzar els gestos. Per desactivar-los, ves a Configuració."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Has completat el gest per canviar d\'aplicació"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Llisca per canviar d\'aplicació"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancel·la"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador de la Barra de tasques"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # aplicació més.}other{Mostra # aplicacions més.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # aplicació per a ordinadors.}other{Mostra # aplicacions per a ordinadors.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicació més}other{aplicacions més}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Escriptori"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bombolla"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Desbordament"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 6e432de..3047d05 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Počítač"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žádné položky z nedávné doby"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
@@ -91,7 +92,7 @@
<string name="allset_hint" msgid="459504134589971527">"Přejetím nahoru se vrátíte na plochu"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Klepnutím na tlačítko plochy se vrátíte na plochu"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> můžete začít používat"</string>
- <string name="default_device_name" msgid="6660656727127422487">"zařízení"</string>
+ <string name="default_device_name" msgid="6660656727127422487">"Zařízení"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavení navigace v systému"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Sdílet"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Zrušit"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdělovač panelu aplikací"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobrazit # další aplikaci.}few{Zobrazit # další aplikace.}many{Zobrazit # další aplikace.}other{Zobrazit # dalších aplikací.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobrazit # aplikaci pro počítač.}few{Zobrazit # aplikace pro počítač.}many{Zobrazit # aplikace pro počítač.}other{Zobrazit # aplikací pro počítač.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{další aplikace}few{další aplikace}many{další aplikace}other{dalších aplikací}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbalovací nabídka"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index c73f49c..6e2130c 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frit format"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Computertilstand"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Computer"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Indstillinger for appforbrug"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ryd alt"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuller"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Opdeling af proceslinjen"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app mere.}one{Vis # app mere.}other{Vis # apps mere.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # computerprogram.}one{Vis # computerprogram.}other{Vis # computerprogrammer.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{yderligere app}one{yderligere app}other{yderligere apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overløb"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 8f571ce..54961fe 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopmodus"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktopmodus"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Alle Apps schließen"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Abbrechen"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskleisten-Teiler"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# Desktop-App anzeigen.}other{# Desktop-Apps anzeigen.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{weitere App}other{weitere Apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktopmodus"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Weitere Optionen"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 011c800..6cbb833 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Καρφίτσωμα"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Ελεύθερη μορφή"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Υπολογιστής"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Υπολογιστής"</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>
@@ -67,7 +68,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>
@@ -90,7 +91,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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Διαχωριστικό Γραμμής εργαλείων"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Μετακίνηση κάτω/δεξιά"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Εμφάνιση # ακόμα εφαρμογής.}other{Εμφάνιση # ακόμα εφαρμογών.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Εμφάνιση # εφαρμογής υπολογιστή.}other{Εμφάνιση # εφαρμογών υπολογιστή.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ακόμη εφαρμογή}other{ακόμη εφαρμογές}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Υπολογιστής"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Συννεφάκι"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Υπερχείλιση"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index c63e094..dcbaa7a 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,7 +100,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 organisation"</string>
@@ -130,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 2183919..c00e6cd 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,7 +100,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>
@@ -140,8 +141,8 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar Divider"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index c63e094..dcbaa7a 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,7 +100,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 organisation"</string>
@@ -130,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index c63e094..dcbaa7a 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,7 +100,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 organisation"</string>
@@ -130,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index ba55585..2abef91 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -99,7 +100,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>
@@ -140,8 +141,8 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar Divider"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 7df97ef..f09fae6 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -22,6 +22,7 @@
<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">"Escritorio"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Computadoras"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Cerrar todo"</string>
@@ -99,7 +100,7 @@
<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>
+ <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">"La app o tu organización no permiten realizar esta acción"</string>
@@ -130,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de la Barra de tareas"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover a la parte superior o izquierda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover a la parte inferior o derecha"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # app más.}other{Mostrar # apps más.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computadoras.}other{Mostrar # apps para computadoras.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ampliada"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 353ff4c..356a38b 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"Ordenador"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de Barra de Tareas"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación más.}other{Mostrar # aplicaciones más.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicaciones para ordenadores.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación más}other{aplicaciones más}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenador"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 6b78c1f..fccbeda 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vabavorm"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Lauaarvuti režiim"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Töölaud"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Rakenduse kasutuse seaded"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
@@ -72,7 +73,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 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Tühista"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tegumiriba jagaja"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Kuva veel # rakendus.}other{Kuva veel # rakendust.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Kuva # töölauarakendus.}other{Kuva # töölauarakendust.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{rakendus veel}other{rakendust veel}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Lauaarvuti"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Mull"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ületäide"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 058ade5..a1d8cc3 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Modu librea"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordenagailua"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Mahaigaina"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Utzi"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Zereginen barraren zatitzailea"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Erakutsi beste # aplikazio.}other{Erakutsi beste # aplikazio.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Erakutsi ordenagailuetarako # aplikazio.}other{Erakutsi ordenagailuetarako # aplikazio.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikazio gehiago}other{aplikazio gehiago}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenagailua"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuila"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Luzapena"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index f6f51b7..8f37686 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"رایانه"</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,11 +100,11 @@
<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>
- <string name="split_widgets_not_supported" msgid="1355743038053053866">"درحالحاضر از ابزارکها پشتیبانی نمیشود، لطفاً برنامه دیگری را انتخاب کنید"</string>
+ <string name="split_widgets_not_supported" msgid="1355743038053053866">"درحالحاضر از ابزارهها پشتیبانی نمیشود، لطفاً برنامه دیگری را انتخاب کنید"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"آموزش گامبهگام پیمایش رد شود؟"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"میتوانید آن را بعداً در برنامه <xliff:g id="NAME">%1$s</xliff:g> پیدا کنید"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"لغو"</string>
@@ -130,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"جداکننده نوار وظیفه"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"انتقال به بالا/ چپ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"انتقال به پایین/ راست"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{نمایش # برنامه دیگر.}one{نمایش # برنامه دیگر.}other{نمایش # برنامه دیگر.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{نمایش # برنامه رایانه.}one{نمایش # برنامه رایانه.}other{نمایش # برنامه رایانه.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{برنامه دیگر}one{برنامه دیگر}other{برنامه دیگر}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"رایانه"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"حبابک"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"سرریز"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 91f64ed..175a896 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vapaamuotoinen"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Tietokone"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Tietokone"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Sovelluksen käyttöasetukset"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Poista kaikki"</string>
@@ -72,7 +73,7 @@
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Hienoa!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pyyhkäise ylös näytön alareunasta"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Kokeile pitää ikkunaa painettuna pidempään ennen kuin päästät irti"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Muista pyyhkäistä suoraan ylöspäin ja pysähdy sitten"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pyyhkäise suoraan ylöspäin ja pysähdy sitten"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Olet oppinut käyttämään eleitä. Jos haluat laittaa eleet pois päältä, avaa Asetukset."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Olet oppinut sovellusten vaihtamiseleen"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Vaihda sovellusta pyyhkäisemällä"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Peru"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tehtäväpalkin jakaja"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Näytä # muu sovellus.}other{Näytä # muuta sovellusta.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Näytä # työpöytäsovellus.}other{Näytä # työpöytäsovellusta.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{muu sovellus}other{muuta sovellusta}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Tietokone"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kupla"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ylivuoto"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index e567239..6d6c67c 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur de bureau"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Ordinateur de bureau"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'appli"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de la barre des tâches"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli.}one{Afficher # autre appli.}other{Afficher # autres applis.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre appli}one{autre appli}other{autres applis}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordinateur de bureau"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bulle à développer"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index ddab232..a395266 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Ordinateur"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -88,7 +89,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>
@@ -96,10 +97,10 @@
<string name="action_share" msgid="2648470652637092375">"Partager"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
<string name="action_split" msgid="2098009717623550676">"Partager"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Enregistrer la paire d\'applis"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Enregistrer une 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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annuler"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de barre des tâches"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli}one{Afficher # autre appli}other{Afficher # autre applis}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # application de bureau.}one{Afficher # application de bureau.}other{Afficher # applications de bureau.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre application}one{autre application}other{autres applications}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordinateur"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dépassement"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 053a48f..5b04960 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Ordenador"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración do uso de aplicacións"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
@@ -90,8 +91,8 @@
<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="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
+ <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> 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>
<string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación máis.}other{Mostrar # aplicacións máis.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicacións para ordenadores.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación máis}other{aplicacións máis}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulla"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index a081ab5..fc253bd 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ફ્રિફોર્મ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ડેસ્કટૉપ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ડેસ્કટૉપ"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ટાસ્કબાર વિભાજક"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"સૌથી ઉપર ડાબી બાજુએ ખસેડો"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"સૌથી નીચે જમણી બાજુએ ખસેડો"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{વધુ # ઍપ બતાવો.}one{વધુ # ઍપ બતાવો.}other{વધુ # ઍપ બતાવો.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ડેસ્કટૉપ ઍપ બતાવો.}one{# ડેસ્કટૉપ ઍપ બતાવો.}other{# ડેસ્કટૉપ ઍપ બતાવો.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{વધુ ઍપ}one{વધુ ઍપ}other{વધુ ઍપ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ડેસ્કટૉપ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"બબલ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ઓવરફ્લો"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 1e74c4a..30a17db 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करें"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ़्रीफ़ॉर्म"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटॉप"</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>
@@ -92,14 +93,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिवाइडर"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ऊपर/बाईं तरफ़ ले जाएं"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"नीचे/दाईं तरफ़ ले जाएं"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# और ऐप्लिकेशन दिखाएं.}one{# और ऐप्लिकेशन दिखाएं.}other{# और ऐप्लिकेशन दिखाएं.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}one{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}other{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ज़्यादा ऐप्लिकेशन}one{ज़्यादा ऐप्लिकेशन}other{ज़्यादा ऐप्लिकेशन}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओवरफ़्लो"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index fc85be9..06511e9 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Računalo"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Radna površina"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke upotrebe aplikacija"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Izbriši sve"</string>
@@ -47,7 +48,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Zakrenite uređaj"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Zakrenite uređaj da biste dovršili vodič o navigaciji pokretima"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pazite da prijeđete prstom od krajnjeg desnog ili krajnjeg lijevog ruba"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prijeđite prstom od krajnjeg desnog ili krajnjeg lijevog ruba"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pazite da prijeđete prstom od desnog ili lijevog ruba do sredine zaslona i podignite prst"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prijeći prstom zdesna da biste se vratili. Sad saznajte kako promijeniti aplikaciju."</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Izvršili ste pokret za povratak. Sad saznajte kako promijeniti aplikaciju."</string>
@@ -70,9 +71,9 @@
<string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Otvaranje početnog zaslona"</string>
<string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Prijeđite prstom od dna zaslona prema gore"</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Sjajno!"</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pazite da prijeđete prstom prema gore od donjeg ruba zaslona"</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Prijeđite prstom prema gore od donjeg ruba zaslona"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Pokušajte zadržati prozor dulje prije podizanja prsta"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pazite da prijeđete prstom ravno prema gore, a zatim zastanete"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Prijeđite prstom ravno prema gore, a zatim zastanite"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste koristiti pokrete. Pokrete možete isključiti u postavkama."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Izvršili ste pokret za promjenu aplikacije"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Povlačenje prstom za promjenu aplikacije"</string>
@@ -91,7 +92,7 @@
<string name="allset_hint" msgid="459504134589971527">"Prijeđite prstom prema gore da biste otvorili početni zaslon"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite gumb početnog zaslona da biste prešli na početni zaslon"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> je spreman za početak upotrebe"</string>
- <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
+ <string name="default_device_name" msgid="6660656727127422487">"Uređaj"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sustavom"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Podijeli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake sa zadacima"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # računalnu aplikaciju.}one{Prikaži # računalnu aplikaciju.}few{Prikaži # računalne aplikacije.}other{Prikaži # računalnih aplikacija.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Računalo"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dodatni izbornik"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 3a539d4..9bd9478 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Asztali"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Asztali"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
@@ -59,7 +60,7 @@
<string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Ha vissza szeretne térni a legutóbbi képernyőre, csúsztasson gyorsan két ujjal a képernyő bal vagy jobb széléről a közepe felé."</string>
<string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Vissza"</string>
<string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Csúsztasson bal vagy jobb szélről a képernyő közepe felé."</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Csúsztasson felfelé a képernyő aljától."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Csúsztasson felfelé a képernyő alsó szélétől."</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Ne álljon meg, mielőtt elengedi a képernyőt."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Csúsztasson egyenesen felfelé."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Teljesítette a kezdőképernyőre lépés kézmozdulatát. Most megtanulhatja, hogyan léphet vissza."</string>
@@ -68,9 +69,9 @@
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Csúsztassa ujját felfelé a képernyő aljától. Ez a mozdulat mindig a kezdőképernyőre visz."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Csúsztasson felfelé két ujjal a képernyő aljáról. Ez a kézmozdulat mindig a kezdőképernyőre viszi."</string>
<string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ugrás a kezdőképernyőre"</string>
- <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Húzza ujját felfelé a képernyő aljától."</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Csúsztasson felfelé a képernyő aljától."</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Kiváló!"</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Csúsztasson felfelé a képernyő aljától."</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Csúsztasson felfelé a képernyő alsó szélétől."</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Próbálja tovább lenyomva tartani az ablakot, mielőtt elengedi a képernyőt."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Csúsztasson egyenesen felfelé, majd várjon egy kicsit"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Eddig megismerhette a kézmozdulatok használatát. A kézmozdulatokat a Beállításokban kapcsolhatja ki."</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Mégse"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Feladatsáv-elválasztó"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# további alkalmazás megjelenítése.}other{# további alkalmazás megjelenítése.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# asztali alkalmazás megjelenítése.}other{# asztali alkalmazás megjelenítése.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{további alkalmazás}other{további alkalmazás}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Asztali"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Buborék"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Túlcsordulás"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index d8503f3..e1481ec 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Կամայական ձև"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Համակարգիչ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Համակարգիչ"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Հավելվածների վահանակի բաժանիչ"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Տեղափոխել ներքևի աջ անկյուն"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Ցուցադրել ևս # հավելված։}one{Ցուցադրել ևս # հավելված։}other{Ցուցադրել ևս # հավելված։}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ցույց տալ # համակարգչային հավելված։}one{Ցույց տալ # համակարգչային հավելված։}other{Ցույց տալ # համակարգչային հավելված։}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{լրացուցիչ հավելված}one{լրացուցիչ հավելված}other{լրացուցիչ հավելված}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Համակարգիչ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ամպիկ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Լրացուցիչ ընտրացանկ"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index d4def8d..f8345b5 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
@@ -79,7 +80,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 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Batal"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pemisah Taskbar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tampilkan # aplikasi desktop.}other{Tampilkan # aplikasi desktop.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikasi lainnya}other{aplikasi lainnya}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tambahan"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index f2dd60c..017d108 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Tölva"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Tölva"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Hætta við"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skipting forritastiku"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Sýna # forrit í viðbót.}one{Sýna # forrit í viðbót.}other{Sýna # forrit í viðbót.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Sýna # skjáborðsforrit.}one{Sýna # skjáborðsforrit.}other{Sýna # skjáborðsforrit.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{forrit til viðbótar}one{forrit til viðbótar}other{forrit til viðbótar}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Skjáborð"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Blaðra"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Yfirflæði"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 9ed28c1..1983ee3 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Annulla"</string>
<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>
@@ -140,8 +141,8 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisore barra delle app"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # altra app.}other{Mostra altre # app.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # app desktop.}other{Mostra # app desktop.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{altra app}other{altre app}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Fumetto"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Extra"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index da8b37d..a7115e3 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"מצב חופשי"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"במחשב"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"מחשב"</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,8 +73,8 @@
<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_complete_with_follow_up" msgid="3544611727467765026">"למדת איך להשתמש בתנועות. ניתן להשבית את התנועות ב\'הגדרות\'."</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>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"כדי לעבור בין אפלקציות, יש להחליק למעלה מתחתית המסך, להחזיק ולאחר מכן לשחרר."</string>
@@ -88,18 +89,18 @@
<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_button_hint" msgid="2395219947744706291">"כדי לעבור אל מסך הבית יש להקיש על הלחצן הראשי"</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>
- <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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"המחיצה בסרגל האפליקציות"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{הצגת אפליקציה אחת (#) נוספת.}one{הצגת # אפליקציות נוספות.}two{הצגת # אפליקציות נוספות.}other{הצגת # אפליקציות נוספות.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{הצגת אפליקציה אחת (#) למחשב.}one{הצגת # אפליקציות למחשב.}two{הצגת # אפליקציות למחשב.}other{הצגת # אפליקציות למחשב.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{אפליקציה נוספת}one{אפליקציות נוספות}two{אפליקציות נוספות}other{אפליקציות נוספות}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"מחשב"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"בועה"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"אפשרויות נוספות"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 54f51da..fa3c01d 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"パソコン"</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 +100,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>
@@ -140,8 +141,8 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"タスクバーの区切り"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"下 / 右に移動"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{他 # 件のアプリを表示できます。}other{他 # 件のアプリを表示できます。}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# 個のデスクトップ アプリが表示されます。}other{# 個のデスクトップ アプリが表示されます。}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個のその他のアプリ}other{個のその他のアプリ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"パソコン"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ふきだし"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"オーバーフロー"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 5328012..a032731 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"თავისუფალი ფორმა"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"დესკტოპი"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"დესკტოპი"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ამოცანათა ზოლის გამყოფი"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ზემოთ/მარცხნივ გადატანა"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ქვემოთ/მარჯვნივ გადატანა"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{#-ით მეტი აპის ჩენება}other{#-ით მეტი აპის ჩვენება.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# დესკტოპის აპის ჩვენება.}other{# დესკტოპის აპის ჩვენება.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{სხვა აპი}other{სხვა აპი}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"დესკტოპი"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ბუშტი"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"გადავსება"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 54c1795..e1a9e8e 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Еркін форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Жұмыс үстелі"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапсырмалар жолағын бөлгіш"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жоғары/солға жылжыту"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмен/оңға жылжыту"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Тағы # қолданбаны көрсету.}other{Тағы # қолданбаны көрсету.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерге арналған # қолданбаны көрсету}other{Компьютерге арналған # қолданбаны көрсету}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{қосымша қолданба}other{қосымша қолданба}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Қалқыма терезе"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Қосымша мәзір"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 698f33c..2eb3114 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"អេក្រង់ដើម"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"បន្ទាត់ខណ្ឌចែករបារកិច្ចការ"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{បង្ហាញកម្មវិធី # ទៀត។}other{បង្ហាញកម្មវិធី # ទៀត។}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}other{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{កម្មវិធីច្រើនទៀត}other{កម្មវិធីច្រើនទៀត}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"អេក្រង់ដើម"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ផ្ទាំងសារ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ម៉ឺនុយបន្ថែម"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 6a86e38..bb60620 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ಮುಕ್ತಸ್ವರೂಪ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ಡೆಸ್ಕ್ಟಾಪ್"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ಡೆಸ್ಕ್ಟಾಪ್"</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>
@@ -73,13 +74,13 @@
<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_complete_with_follow_up" msgid="3544611727467765026">"ಗೆಶ್ಚರ್ಗಳನ್ನು ಬಳಸುವುದು ಹೇಗೆಂದು ನೀವು ತಿಳಿದುಕೊಂಡಿರುವಿರಿ. ಗೆಶ್ಚರ್ಗಳನ್ನು ಆಫ್ ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."</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>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ಆ್ಯಪ್ಗಳ ನಡುವೆ ಬದಲಿಸಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"ಆ್ಯಪ್ಗಳ ನಡುವೆ ಬದಲಿಸಲು, 2 ಬೆರಳುಗಳಿಂದ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ."</string>
<string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸಿ"</string>
- <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹೋಲ್ಡ್ ಮಾಡಿ, ನಂತರ ಬಿಡುಗಡೆ ಮಾಡಿ"</string>
+ <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹೋಲ್ಡ್ ಮಾಡಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ"</string>
<string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"ಭೇಷ್!"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"ಸಂಪೂರ್ಣ ಸಿದ್ಧವಾಗಿದೆ"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"ಮುಗಿದಿದೆ"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ಟಾಸ್ಕ್ಬಾರ್ ಡಿವೈಡರ್"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ಮೇಲಿನ/ಎಡಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ಕೆಳಗಿನ/ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ಇನ್ನೂ # ಆ್ಯಪ್ ಅನ್ನು ತೋರಿಸಿ.}one{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ ತೋರಿಸಿ.}one{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ಹೆಚ್ಚಿನ ಆ್ಯಪ್}one{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}other{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ಡೆಸ್ಕ್ಟಾಪ್"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ಬಬಲ್"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ಓವರ್ಫ್ಲೋ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 31942fb..e6a80c3 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"고정"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"자유 형식"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"데스크톱"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"데스크톱"</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>
@@ -90,7 +91,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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"태스크 바 분할"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{앱 #개 더 표시}other{앱 #개 더 표시}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{데스크톱 앱 #개를 표시합니다.}other{데스크톱 앱 #개를 표시합니다.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{추가 앱}other{추가 앱}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"데스크톱"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"더보기"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 8805bd0..04e7f6e 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Эркин форма режими"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Компьютер"</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>
@@ -90,8 +91,8 @@
<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="default_device_name" msgid="6660656727127422487">"түзмөк"</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>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапшырмалар панелин бөлгүч"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмөнкү/оң бурчка жылдыруу"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Дагы # колдонмону көрсөтүү.}other{Дагы # колдонмону көрсөтүү.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# иш такта колдонмосун көрсөтүү.}other{# иш такта колдонмосун көрсөтүү.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{колдонмо бар}other{колдонмо бар}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Көбүкчө"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Кошумча меню"</string>
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index e862b9e..2239f8b 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -83,7 +83,7 @@
<dimen name="taskbar_suw_frame">96dp</dimen>
<dimen name="taskbar_suw_insets">24dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_width">205dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_height">119dp</dimen>
+ <!-- Keyboard Quick Switch -->
+ <dimen name="keyboard_quick_switch_taskview_width">217.6dp</dimen>
</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 9e70a5c..b3ca116 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ຮູບແບບອິດສະຫລະ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ເດັສທັອບ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ເດັສທັອບ"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ເສັ້ນແບ່ງແຖບໜ້າວຽກ"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ສະແດງອີກ # ແອັບ.}other{ສະແດງອີກ # ແອັບ.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}other{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ແອັບເພີ່ມເຕີມ}other{ແອັບເພີ່ມເຕີມ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ເດັສທັອບ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ຟອງ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ລາຍການເພີ່ມເຕີມ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index f78fa30..4f3f36e 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Stalinis kompiuteris"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Stalinis kompiuteris"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Atšaukti"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Užduočių juostos daliklis"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rodyti dar # programą.}one{Rodyti dar # programą.}few{Rodyti dar # programas.}many{Rodyti dar # programos.}other{Rodyti dar # programų.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rodyti # darbalaukio programą.}one{Rodyti # darbalaukio programą.}few{Rodyti # darbalaukio programas.}many{Rodyti # darbalaukio programos.}other{Rodyti # darbalaukio programų.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildoma programa}one{papildoma programa}few{papildomos programos}many{papildomos programos}other{papildomų programų}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Stalinis kompiuteris"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulas"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Perpildymas"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 799e8d1..fd75fc4 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Brīva forma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Dators"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Darbvirsma"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Lietotņu izmantošanas iestatījumi"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Notīrīt visu"</string>
@@ -67,7 +68,7 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Vilkšana, lai pārietu uz sākumu"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Velciet augšup no ekrāna apakšdaļas. Ar šo žestu vienmēr varat atvērt sākuma ekrānu."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Ar 2 pirkstiem velciet augšup no ekrāna apakšdaļas. Ar šo žestu vienmēr varat atvērt sākuma ekrānu."</string>
- <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Došanās uz sākuma ekrānu"</string>
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Doties uz sākuma ekrānu"</string>
<string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Velciet augšup no ekrāna apakšdaļas."</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Lieliski!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Jāvelk augšup no ekrāna apakšmalas."</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Atcelt"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Uzdevumu joslas atdalītājs"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rādīt vēl # lietotni}zero{Rādīt vēl # lietotnes}one{Rādīt vēl # lietotni}other{Rādīt vēl # lietotnes}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rādīt # datora lietotni.}zero{Rādīt # datora lietotnes.}one{Rādīt # datora lietotni.}other{Rādīt # datora lietotnes.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildu lietotne}zero{papildu lietotņu}one{papildu lietotne}other{papildu lietotnes}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Darbvirsma"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulis"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Pārpilde"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 04f35ba..b50277b 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"За компјутер"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник на „Лента со задачи“"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести долу десно"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи уште # апликација.}one{Прикажи уште # апликација.}other{Прикажи уште # апликации.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликација за компјутер.}one{Прикажи # апликација за компјутер.}other{Прикажи # апликации за компјутер.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнителна апликација}one{дополнителна апликација}other{дополнителни апликации}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за компјутер"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Проширено балонче"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 0db3e1f..ef72da1 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ഫ്രീഫോം"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ഡെസ്ക്ടോപ്പ്"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ഡെസ്ക്ടോപ്പ്"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ടാസ്ക്ബാർ ഡിവൈഡർ"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ആപ്പ് കൂടി കാണിക്കുക.}other{# ആപ്പുകൾ കൂടി കാണിക്കുക.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ഡെസ്ക്ടോപ്പ് ആപ്പ് കാണിക്കുക.}other{# ഡെസ്ക്ടോപ്പ് ആപ്പുകൾ കാണിക്കുക.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{കൂടുതൽ ആപ്പ്}other{കൂടുതൽ ആപ്പുകൾ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ഡെസ്ക്ടോപ്പ്"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ബബിൾ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ഓവർഫ്ലോ"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index a76117a..2ca2e26 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бэхлэх"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Чөлөөтэй хувьсах"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Дэлгэц"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ажлын хэсгийг хуваагч"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Зүүн дээд хэсэг рүү зөөх"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Баруун доод хэсэг рүү зөөх"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Өөр # аппыг харуулна уу.}other{Өөр # аппыг харуулна уу.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерын # аппыг харуулна уу.}other{Компьютерын # аппыг харуулна уу.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{бусад апп}other{бусад апп}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Дэлгэц"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Илүү хэсэг"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 09f40ab..159368d 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रीफॉर्म"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटॉप"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार विभाजक"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सर्वात वरती/डावीकडे हलवा"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"तळाशी/उजवीकडे हलवा"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{आणखी # अॅप दाखवा.}other{आणखी # अॅप्स दाखवा.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप अॅप दाखवा.}other{# डेस्कटॉप अॅप्स दाखवा.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{आणखी अॅप}other{आणखी अॅप्स}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओव्हरफ्लो"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 72887ef..9a27e51 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk bebas"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
@@ -68,18 +69,18 @@
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Leret ke atas dari bahagian bawah skrin. Gerak isyarat ini sentiasa membawa anda ke Skrin utama."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Leret ke atas dengan 2 jari dari bawah skrin. Gerak isyarat ini sentiasa bawa anda ke Skrin utama."</string>
<string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Pergi ke skrin utama"</string>
- <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Leret ke atas dari bahagian bawah skrin anda"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Leret ke atas dari bahagian bawah skrin"</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Syabas!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pastikan anda meleret ke atas dari sisi bahagian bawah skrin"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Cuba tahan tetingkap untuk tempoh yang lebih lama sebelum melepaskan"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pastikan anda meleret terus ke atas, kemudian menjeda"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pastikan anda meleret lurus ke atas, kemudian berhenti seketika"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Anda sudah belajar cara menggunakan gerak isyarat. Untuk mematikan gerak isyarat, pergi ke Tetapan."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Anda telah melengkapkan gerak isyarat menukar apl"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Leret untuk menukar apl"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Untuk beralih antara apl, leret ke atas dari bahagian bawah skrin anda, tahan, kemudian lepaskan."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Untuk beralih antara apl, leret ke atas dengan 2 jari dari bawah skrin, tahan, kemudian lepaskan."</string>
<string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Beralih antara apl"</string>
- <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Leret ke atas dari bahagian bawah skrin anda, tahan, kemudian lepaskan"</string>
+ <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Leret ke atas dari bahagian bawah skrin, tahan, kemudian lepas"</string>
<string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Syabas!"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Selesai"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Selesai"</string>
@@ -99,7 +100,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>
@@ -140,8 +141,8 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pembahagi Bar Tugas"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tunjukkan # lagi apl.}other{Tunjukkan # lagi apl.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tunjukkan # apl desktop.}other{Tunjukkan # apl desktop.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{apl lagi}other{apl lagi}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Gelembung"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Limpahan"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 749c1b5..7e298fb 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးရန်"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"အလွတ်ပုံစံ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ဒက်စ်တော့"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ဒက်စ်တော့"</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>
@@ -47,7 +48,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ကြိုတင်မှန်းဆထားသော အက်ပ်− <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"သင့်စက်ကို လှည့်ပါ"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"လက်ဟန်ဖြင့် လမ်းညွှန်ခြင်း ရှင်းလင်းပို့ချချက်အား အပြီးသတ်ရန် သင့်စက်ကို လှည့်ပါ"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ညာ (သို့) ဘယ်အစွန်း၏ ခပ်လှမ်းလှမ်းမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ညာ (သို့) ဘယ်ဘက်အစွန်ဆုံးမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ဖန်သားပြင်၏ ညာ (သို့) ဘယ်အစွန်းမှ အလယ်သို့ ပွတ်ဆွဲပြီး လွှတ်လိုက်ကြောင်း သေချာပါစေ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"နောက်ပြန်သွားရန် ညာဘက်မှပွတ်ဆွဲနည်းကို သိသွားပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"နောက်ဆုတ်လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"လုပ်ဆောင်စရာဘား ပိုင်းခြားစနစ်"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{နောက်ထပ်အက်ပ် # ခု ပြပါ။}other{နောက်ထပ်အက်ပ် # ခု ပြပါ။}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}other{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{နောက်ထပ်အက်ပ်}other{နောက်ထပ်အက်ပ်များ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ဒက်စ်တော့"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ပူဖောင်းကွက်"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"မီနူးအပို"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 245945b..4b982ef 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Skrivebord"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Skrivebord"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Avbryt"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skille for oppgavelinjen"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app til.}other{Vis # apper til.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # datamaskinprogram.}other{Vis # datamaskinprogrammer.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app til}other{apper til}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Datamaskin"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflyt"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index f881637..326222b 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटप"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटप"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिभाइडर"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{थप # एप देखाउनुहोस्।}other{थप # वटा एप देखाउनुहोस्।}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटप एप देखाउनुहोस्।}other{# वटा डेस्कटप एप देखाउनुहोस्।}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{थप एप}other{थप एपहरू}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटप"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओभरफ्लो"</string>
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index 2cb633a..eb88310 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -14,16 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-
- <style name="AllSetTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar">
- <item name="android:navigationBarColor">@android:color/transparent</item>
- <item name="android:statusBarColor">@android:color/transparent</item>
- <item name="android:enforceNavigationBarContrast">false</item>
- <item name="android:windowLightStatusBar">false</item>
- <item name="android:windowBackground">@android:color/transparent</item>
- </style>
+<resources>
<style name="TextAppearance.GestureTutorial.MainTitle.Home"
parent="TextAppearance.GestureTutorial.MainTitle">
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 09f8aca..8a923b5 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vrije vorm"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Instellingen voor app-gebruik"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Alles wissen"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Scheiding voor Taakbalk"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Nog # app tonen.}other{Nog # apps tonen.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# desktop-app tonen.}other{# desktop-apps tonen.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{extra app}other{extra apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbel"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overloop"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 83522f3..3150ded 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ପିନ୍"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ଫ୍ରିଫର୍ମ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ଡେସ୍କଟପ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ଡେସ୍କଟପ"</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>
@@ -47,7 +48,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ପୂର୍ବାନୁମାନ କରାଯାଇଥିବା ଆପ୍: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"ଆପଣଙ୍କ ଡିଭାଇସକୁ ରୋଟେଟ କରନ୍ତୁ"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"ଜେଶ୍ଚର ନାଭିଗେସନ ଟ୍ୟୁଟୋରିଆଲ ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ଦୟାକରି ଆପଣଙ୍କ ଡିଭାଇସ ରୋଟେଟ କରନ୍ତୁ"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ଆପଣ ସ୍କ୍ରିନର ଏକଦମ୍-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ଆପଣ ସ୍କ୍ରିନର ଏକଦମ-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ଆପଣ ସ୍କ୍ରିନର ଡାହାଣ ବା ବାମ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ଆପଣ ଡାହାଣରୁ ସ୍ୱାଇପ୍ କରି ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣିଲେ। ତା\'ପରେ, ଆପକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ଆପଗୁଡ଼ିକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
@@ -72,14 +73,14 @@
<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>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ଆପ୍ସ ମଧ୍ୟରେ ସୁଇଚ କରିବାକୁ, ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ, ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ କରନ୍ତୁ।"</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"ଆପ୍ସ ମଧ୍ୟରେ ସ୍ୱିଚ କରିବାକୁ, 2ଟି ଆଙ୍ଗୁଠିରେ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ କର।"</string>
<string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"ଆପ୍ସ ସୁଇଚ କରନ୍ତୁ"</string>
- <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ଆପଣଙ୍କ ସ୍କ୍ରିନ୍ର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରି ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ୍ କରନ୍ତୁ"</string>
+ <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"ଆପଣଙ୍କ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ କରନ୍ତୁ"</string>
<string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"ବହୁତ ବଢ଼ିଆ!"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"ସବୁ ପ୍ରସ୍ତୁତ"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"ହୋଇଗଲା"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ଟାସ୍କବାର ଡିଭାଇଡର"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ଅଧିକ #ଟି ଆପ ଦେଖାନ୍ତୁ।}other{ଅଧିକ #ଟି ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ଡେସ୍କଟପ ଆପ ଦେଖାନ୍ତୁ।}other{# ଡେସ୍କଟପ ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ଅଧିକ ଆପ}other{ଅଧିକ ଆପ୍ସ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ଡେସ୍କଟପ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ବବଲ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ଓଭରଫ୍ଲୋ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 197fc6c..7da7555 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ਫ੍ਰੀਫਾਰਮ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ਡੈਸਕਟਾਪ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ਡੈਸਕਟਾਪ"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ਟਾਸਕਬਾਰ ਵਿਭਾਜਕ"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ਸਿਖਰਲੇ/ਖੱਬੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ਹੇਠਾਂ/ਸੱਜੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}one{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}other{# ਹੋਰ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}one{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}other{# ਡੈਸਕਟਾਪ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ਹੋਰ ਐਪ}one{ਹੋਰ ਐਪ}other{ਹੋਰ ਐਪਾਂ}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ਡੈਸਕਟਾਪ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ਬਬਲ"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ਓਵਰਫ਼ਲੋ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 5d6d927..0cc49e2 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Przypnij"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Tryb dowolny"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Pulpit"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Pulpit"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ustawienia użycia aplikacji"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Wyczyść wszystko"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Linia dzielenia paska aplikacji"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaż jeszcze # aplikację.}few{Pokaż jeszcze # aplikacje.}many{Pokaż jeszcze # aplikacji.}other{Pokaż jeszcze # aplikacji.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Pokaż # aplikację komputerową.}few{Pokaż # aplikacje komputerowe.}many{Pokaż # aplikacji komputerowych.}other{Pokaż # aplikacji komputerowej.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{inna aplikacja}few{inne aplikacje}many{innych aplikacji}other{innej aplikacji}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Pulpit"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Dymek"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozwijany"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 4787ec3..33b87df 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -22,6 +22,7 @@
<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_desktop" msgid="8081113562549637334">"Computador"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Definições de utilização de aplicações"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
@@ -47,7 +48,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App prevista: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Rode o dispositivo"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Rode o seu dispositivo para concluir o tutorial de navegação por gestos"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize rapidamente a partir da extremidade mais à direita ou mais à esquerda"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize a partir da extremidade mais à direita ou mais à esquerda"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Deslize rapidamente a partir da extremidade esquerda ou direita até ao centro do ecrã e solte"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Aprendeu a deslizar a partir da direita para retroceder. A seguir, saiba como alternar entre apps."</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Concluiu o gesto para retroceder. A seguir, saiba como alternar entre apps."</string>
@@ -58,8 +59,8 @@
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Para voltar ao último ecrã, deslize rapidamente do limite esquerdo ou direito até ao centro do ecrã."</string>
<string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Para voltar ao último ecrã, deslize rapidamente com 2 dedos a partir da extremidade esquerda ou direita até ao centro do ecrã."</string>
<string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Retroceder"</string>
- <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Deslize rapidamente a partir da extremidade esquerda ou direita para o meio do ecrã"</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Deslize rapidamente com o dedo a partir do limite inferior do ecrã"</string>
+ <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Deslize a partir da extremidade esquerda ou direita até ao centro do ecrã"</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Deslize a partir do limite inferior do ecrã"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Não faça uma pausa antes de soltar"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Deslize rapidamente com o dedo para cima"</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Concluiu o gesto para aceder ao ecrã principal. A seguir, saiba como retroceder."</string>
@@ -68,18 +69,18 @@
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Deslize rapidamente para cima a partir da parte inferior. Este gesto abre sempre o ecrã principal."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Deslize rapidamente para cima com 2 dedos no fundo do ecrã. Este gesto abre sempre o ecrã principal."</string>
<string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Aceda ao ecrã principal"</string>
- <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Deslize rapidamente para cima a partir da parte inferior do ecrã"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Deslize para cima a partir da parte inferior do ecrã"</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Muito bem!"</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Deslize rapidamente com o dedo a partir do limite inferior do ecrã"</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Deslize a partir do limite inferior do ecrã"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Experimente premir a janela durante mais tempo antes de soltar"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Garanta que desliza rapidamente com o dedo para cima e, em seguida, faz uma pausa"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima e pause"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Aprendeu a utilizar gestos. Para desativar os gestos, aceda às Definições."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Concluiu o gesto para alternar entre apps"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Deslize rapidamente com o dedo para alternar entre apps"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Para alternar entre apps, deslize para cima sem soltar a partir da parte inferior do ecrã e solte."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Para mudar de app, deslize rapidamente para cima com 2 dedos sem soltar no fundo do ecrã e solte."</string>
<string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Mude de app"</string>
- <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Deslize rapidamente para cima a partir da parte inferior do ecrã sem soltar e, em seguida, solte"</string>
+ <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Deslize para cima a partir da parte inferior do ecrã , detenha o gesto e solte"</string>
<string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Muito bem!"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Está tudo pronto"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Concluído"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para a parte superior esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para a part superior direita"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outra app}other{outras apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menu adicional"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index cb45f07..0aa6295 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"Computador"</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>
@@ -72,7 +73,7 @@
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Muito bem!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Deslize da borda inferior da tela para cima"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Mantenha a janela pressionada por mais tempo antes de soltar"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima e pare"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima em linha reta e pare"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Você aprendeu. Para desativar os gestos, acesse as Configurações."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Você concluiu o gesto para mudar de app"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Deslizar para trocar de app"</string>
@@ -89,7 +90,7 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string>
<string name="allset_hint" msgid="459504134589971527">"Deslize para cima para acessar a tela inicial"</string>
- <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para ir para a tela inicial"</string>
+ <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para acessar a tela inicial"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Você já pode começar a usar seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configurações de navegação do sistema"</annotation></string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Cancelar"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador da Barra de tarefas"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}one{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}one{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outro app}one{outro app}other{outros apps}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Balão flutuante"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 31b1951..2f9d287 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"Computer"</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 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Anulează"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separator pentru bara de activități"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afișează încă # aplicație}few{Afișează încă # aplicații}other{Afișează încă # de aplicații}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afișează # aplicație pentru computer.}few{Afișează # aplicații pentru computer.}other{Afișează # de aplicații pentru computer.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicație suplimentară}few{mai multe aplicații}other{mai multe aplicații}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Suplimentar"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 72559f6..2722ca9 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"Мультиоконный режим"</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 +73,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>
@@ -92,14 +93,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделитель панели задач"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Переместить вверх или влево"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Переместить вниз или вправо"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показать ещё # приложение}one{Показать ещё # приложение}few{Показать ещё # приложения}many{Показать ещё # приложений}other{Показать ещё # приложения}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показать # компьютерное приложение.}one{Показать # компьютерное приложение.}few{Показать # компьютерных приложения.}many{Показать # компьютерных приложений.}other{Показать # компьютерного приложения.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнительное приложение}one{дополнительное приложение}few{дополнительных приложения}many{дополнительных приложений}other{дополнительного приложения}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим компьютера"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Всплывающая подсказка"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Дополнительное меню"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 6e7aabb..19b61f7 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -22,6 +22,7 @@
<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_desktop" msgid="8081113562549637334">"ඩෙස්ක්ටොපය"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"කාර්ය තීරු බෙදනය"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{තවත් # යෙදුමක් පෙන්වන්න.}one{තවත් යෙදුම් #ක් පෙන්වන්න.}other{තවත් යෙදුම් #ක් පෙන්වන්න.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ඩෙස්ක්ටොප් යෙදුමක් පෙන්වන්න.}one{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}other{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{තව යෙදුම}one{තවත් යෙදුම්}other{තවත් යෙදුම්}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ඩෙස්ක්ටොපය"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"බුබුළු"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"පිටාර යාම"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 5fbe4f1..0f0ec27 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Počítač"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
@@ -47,7 +48,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predpovedaná aplikácia: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Otočte zariadenie"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Otočte zariadenie a dokončite tak návod, ako navigovať gestami"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Musíte potiahnuť úplne z pravého alebo ľavého okraja"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Musíte potiahnuť úplne z pravého alebo ľavého okraja."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Musíte potiahnuť z pravého alebo ľavého okraja do stredu obrazovky a potom uvoľniť"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste sa prejsť späť potiahnutím sprava. V ďalšom kroku sa naučíte prepínať aplikácie."</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dokončili ste gesto na prechod späť. V ďalšom kroku sa naučíte, ako prepínať aplikácie."</string>
@@ -58,8 +59,8 @@
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Na poslednú obrazovku prejdete potiahnutím z ľavého alebo pravého okraja do stredu obrazovky."</string>
<string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Na poslednú obrazovku sa vrátite potiahnutím dvoma prstami z ľavého alebo pravého okraja do stredu obrazovky."</string>
<string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Prechod späť"</string>
- <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Potiahnite z ľavého alebo pravého okraja do stredu obrazovky"</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Musíte potiahnuť nahor z dolného okraja obrazovky"</string>
+ <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Potiahnite z ľavého alebo pravého okraja do stredu obrazovky."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Musíte potiahnuť nahor z dolného okraja obrazovky."</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Pred uvoľnením nesmiete zastať"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Musíte potiahnuť priamo nahor"</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Dokončili ste gesto prechodu na plochu. Teraz sa naučíte, ako sa vrátiť späť."</string>
@@ -68,18 +69,18 @@
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Potiahnite nahor zdola obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Postiahnite dvoma prstami z dolnej časti obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
<string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Prechod na plochu"</string>
- <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Potiahnite z dolnej časti obrazovky nahor"</string>
+ <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Potiahnite z dolnej časti obrazovky nahor."</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Skvelé!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Musíte potiahnuť nahor z dolného okraja obrazovky"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Skúste okno pred uvoľnením podržať dlhšie"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Musite potiahnuť priamo nahor a potom zastať"</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste sa používať gestá. Gestá môžete vypnúť v nastaveniach."</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Musite potiahnuť priamo nahor a potom zastať."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste sa používať gestá. Gestá môžete vypnúť v Nastaveniach."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Dokončili ste gesto na prepnutie aplikácií"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prepínanie aplikácií potiahnutím"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Aplikácie môžete prepínať potiahnutím obrazovky zdola nahor, pridržaním a následným uvoľnením."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Aplikácie prepnete potiahnutím dvoma prstami z dolnej časti obrazovky, ich pridržaním a uvoľnením."</string>
<string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Prepnutie aplikácií"</string>
- <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Potiahnite nahor z dolného okraja obrazovky, pridržte a uvoľnite"</string>
+ <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Potiahnite nahor z dolného okraja obrazovky, pridržte a uvoľnite."</string>
<string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Výborne"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Hotovo"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Hotovo"</string>
@@ -90,7 +91,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 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Zrušiť"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdeľovač panela aplikácií"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobraziť # ďalšiu aplikáciu.}few{Zobraziť # ďalšie aplikácie.}many{Show # more apps.}other{Zobraziť # ďalších aplikácií.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobraziť # aplikáciu pre počítač.}few{Zobraziť # aplikácie pre počítač.}many{Show # desktop apps.}other{Zobraziť # aplikácií pre počítač.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ďalšia aplikácia}few{ďalšie aplikácie}many{ďalšie aplikácie}other{ďalšie aplikácie}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbaľovacia ponuka"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 62c0c3c..972ced5 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Prosta oblika"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Namizni računalnik"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Namizni način"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavitve uporabe aplikacij"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Počisti vse"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelilnik opravilne vrstice"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premakni na vrh/levo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premakni na dno/desno"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaži še # aplikacijo.}one{Pokaži še # aplikacijo.}two{Pokaži še # aplikaciji.}few{Pokaži še # aplikacije.}other{Pokaži še # aplikacij.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaz # aplikacije za namizni računalnik.}one{Prikaz # aplikacije za namizni računalnik.}two{Prikaz # aplikacij za namizni računalnik.}few{Prikaz # aplikacij za namizni računalnik.}other{Prikaz # aplikacij za namizni računalnik.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}two{dodatni aplikaciji}few{dodatne aplikacije}other{dodatnih aplikacij}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Namizni računalnik"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblaček"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oblaček z dodatnimi elementi"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 78f2733..d2a7281 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formë e lirë"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopi"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktopi"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cilësimet e përdorimit të aplikacionit"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Anulo"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ndarësi i shiritit të detyrave"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Shfaq # aplikacion tjetër.}other{Shfaq # aplikacione të tjera.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Shfaq # aplikacion për desktop.}other{Shfaq # aplikacione për desktop.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikacion tjetër}other{aplikacione të tjera}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Flluska"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tejkalimi"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index ee3a467..81204af 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Рачунар"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Рачунари"</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>
@@ -89,7 +90,7 @@
<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_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисти ишли на почетни екран"</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>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Подешавања кретања кроз систем"</annotation></string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник траке задатака"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи још # апликацију.}one{Прикажи још # апликацију.}few{Прикажи још # апликације.}other{Прикажи још # апликација.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликацију за рачунаре.}one{Прикажи # апликацију за рачунаре.}few{Прикажи # апликације за рачунаре.}other{Прикажи # апликација за рачунаре.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{додатна апликација}one{додатна апликација}few{додатне апликације}other{додатних апликација}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Рачунар"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Облачић"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Преклопни"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index e2cf71f..5d0c7a3 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Dator"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Dator"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Listan är tom"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Inställningar för appanvändning"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Rensa alla"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Avbryt"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Avdelare för aktivitetsfältet"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Visa # app till.}other{Visa # appar till.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Visa # datorapp.}other{Visa # datorappar.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app till}other{appar till}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Dator"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbla"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Fler alternativ"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 66feb58..e133ba3 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Kompyuta ya mezani"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Kompyuta ya Mezani"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Acha"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Kitenganishi cha Upauzana"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Onyesha programu # zaidi.}other{Onyesha programu # zaidi.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Onyesha programu # ya kompyuta ya mezani.}other{Onyesha programu # za kompyuta ya mezani.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{programu nyingine}other{programu zingine}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuta ya Mezani"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kiputo"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kiputo cha vipengee vya ziada"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 43e12ee..95d0fa9 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"குறிப்பிட்ட வடிவமில்லாத பயன்முறை"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"டெஸ்க்டாப்"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"டெஸ்க்டாப்"</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 +73,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>
@@ -90,7 +91,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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"செயல் பட்டிப் பிரிப்பான்"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{மேலும் # ஆப்ஸைக் காட்டு.}other{மேலும் # ஆப்ஸைக் காட்டு.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}other{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{கூடுதல் ஆப்ஸ்}other{கூடுதல் ஆப்ஸ்}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"டெஸ்க்டாப்"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"குமிழ்"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index fbe67dc..116d388 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయండి"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"సంప్రదాయేతర"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"డెస్క్టాప్"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"డెస్క్టాప్"</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 +100,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>
@@ -140,8 +141,8 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"టాస్క్బార్ డివైడర్"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"దిగువ/కుడి వైపునకు తరలించండి"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{మరో # యాప్ను చూడండి.}other{మరో # యాప్లను చూడండి.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# డెస్క్టాప్ యాప్ను చూపండి.}other{# డెస్క్టాప్ యాప్లను చూపండి.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{మరో యాప్}other{మరిన్ని యాప్లు}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"డెస్క్టాప్"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"బబుల్"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ఓవర్ఫ్లో"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 7816628..ecdb3b5 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ปักหมุด"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"รูปแบบอิสระ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"เดสก์ท็อป"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"เดสก์ท็อป"</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>
@@ -47,7 +48,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"แอปที่คาดว่าจะใช้: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"หมุนอุปกรณ์ของคุณ"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"โปรดหมุนอุปกรณ์เพื่อทำตามบทแนะนำการนำทางด้วยท่าทางสัมผัสให้เสร็จสมบูรณ์"</string>
- <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ตรวจสอบว่าปัดจากขอบด้านขวาสุดหรือซ้ายสุด"</string>
+ <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ปัดจากขอบด้านขวาสุดหรือซ้ายสุด"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ตรวจสอบว่าปัดจากขอบด้านขวาหรือซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"คุณรู้วิธีปัดจากด้านขวาเพื่อย้อนกลับแล้ว ต่อไปดูวิธีสลับแอป"</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว ต่อไปดูวิธีสลับแอป"</string>
@@ -72,7 +73,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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ตัวแบ่งแถบงาน"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ย้ายไปที่ด้านบนหรือด้านซ้าย"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ย้ายไปที่ด้านล่างหรือด้านขวา"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{แสดงเพิ่มเติมอีก # แอป}other{แสดงเพิ่มเติมอีก # แอป}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{แสดงแอปบนเดสก์ท็อป # รายการ}other{แสดงแอปบนเดสก์ท็อป # รายการ}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{แอปเพิ่มเติม}other{แอปเพิ่มเติม}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"เดสก์ท็อป"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"บับเบิล"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"การดำเนินการเพิ่มเติม"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index e1a77a5..da646a4 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mga setting ng paggamit ng app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"I-clear lahat"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divider ng Taskbar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Magpakita ng # pang app.}one{Magpakita ng # pang app.}other{Magpakita ng # pang app.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ipakita ang # desktop app.}one{Ipakita ang # desktop app.}other{Ipakita ang # na desktop app.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{pang app}one{pang app}other{pang app}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index ef8f50d..7be5464 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Serbest çalışma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Masaüstü"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Uygulama kullanım ayarları"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tümünü temizle"</string>
@@ -90,7 +91,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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Görev Çubuğu Ayırıcısı"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# uygulama daha göster.}other{# uygulama daha göster}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü uygulamasını göster.}other{# masaüstü uygulamasını göster.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{uygulama daha}other{uygulama daha}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Taşma"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 201ac18..216ae0b 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"Комп’ютер"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Розділювач панелі завдань"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показати ще # додаток.}one{Показати ще # додаток.}few{Показати ще # додатки.}many{Показати ще # додатків.}other{Показати ще # додатка.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показати # комп’ютерну програму.}one{Показати # комп’ютерну програму.}few{Показати # комп’ютерні програми.}many{Показати # комп’ютерних програм.}other{Показати # комп’ютерної програми.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{інший додаток}one{інший додаток}few{інші додатки}many{інших додатків}other{іншого додатка}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Комп’ютер"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Повідомлення"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Додаткове повідомлення"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index b2a5c88..2307cb1 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"فری فارم"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ڈیسک ٹاپ"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"ڈیسک ٹاپ"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ٹاسک بار ڈیوائیڈر"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"اوپر/بائیں طرف منتقل کریں"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"نیچے/دائیں طرف منتقل کریں"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# مزید ایپ دکھائیں۔}other{# مزید ایپس دکھائیں۔}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ڈیسک ٹاپ ایپ دکھائیں۔}other{# ڈیسک ٹاپ ایپس دکھائیں۔}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{مزید ایپ}other{مزید ایپس}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"ڈیسک ٹاپ"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ببل"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"اوورفلو"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 6df0b31..9f98b55 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Qadash"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Vazifalar panelini ajratkich"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Yana # ta ilovani chiqarish}other{Yana # ta ilovani chiqarish}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ta desktop ilovani chiqarish.}other{# ta desktop ilovani chiqarish.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{boshqa ilova}other{boshqa ilovalar}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuter"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Pufak"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kengaytirish"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 76eec0c..50acbbc 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Dạng tự do"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Máy tính"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Máy tính"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cài đặt mức sử dụng ứng dụng"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Xóa tất cả"</string>
@@ -99,7 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Đường phân chia Taskbar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Hiện thêm # ứng dụng.}other{Hiện thêm # ứng dụng.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Hiện # ứng dụng dành cho máy tính.}other{Hiện # ứng dụng dành cho máy tính.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ứng dụng khác}other{ứng dụng khác}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Máy tính"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bong bóng"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bong bóng bổ sung"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b5ae26d..1b6c4e4 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"桌面设备"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"任务栏分隔线"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{显示另外 # 个应用。}other{显示另外 # 个应用。}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{显示 # 款桌面应用。}other{显示 # 款桌面应用。}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{多个应用}other{多个应用}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面模式"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢出式气泡框"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index dd52065..38608e5 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"桌面"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個桌面應用程式。}other{顯示 # 個桌面應用程式。}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"對話氣泡"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"展開式"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 6d7652a..3e46779 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -21,7 +21,8 @@
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="recent_task_desktop" msgid="8081113562549637334">"電腦"</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 +100,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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個電腦版應用程式。}other{顯示 # 個電腦版應用程式。}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"電腦"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"泡泡"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢位"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 973ce80..120b387 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -22,6 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ideskithophu"</string>
+ <string name="recent_task_desktop" msgid="8081113562549637334">"Ideskithophu"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
@@ -99,7 +100,7 @@
<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>
+ <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Khansela"</string>
<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,21 +131,18 @@
<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>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Isihlukanisi se-Taskbar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Bonisa i-app e-# ngaphezulu.}one{Bonisa ama-app angu-# ngaphezulu.}other{Bonisa ama-app angu-# ngaphezulu.}}"</string>
- <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Bonisa i-app engu-# yedeskithophu.}one{Bonisa ama-app angu-# wedeskithophu.}other{Bonisa ama-app angu-# wedeskithophu.}}"</string>
+ <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{i-app eyengeziwe}one{ama-app engeziwe}other{ama-app engeziwe}}"</string>
+ <string name="quick_switch_desktop" msgid="8393802056024499749">"Ideskithophu"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ibhamuza"</string>
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ukugcwala kakhulu"</string>
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index ccc7f18..7fd6b5c 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -28,6 +28,7 @@
<!-- Border color for a keyboard quick switch task views -->
<attr name="focusBorderColor" format="color" />
<attr name="hoverBorderColor" format="color" />
+ <attr name="focusBorderRadius" format="dimension" />
</declare-styleable>
<declare-styleable name="ClearAllButton">
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/dimens.xml b/quickstep/res/values/dimens.xml
index 867ce17..ce3f3ac 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -41,6 +41,8 @@
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<!-- The icon size for the focused task, placed in center of touch target -->
<dimen name="task_thumbnail_icon_drawable_size">44dp</dimen>
+ <!-- The splash icon size on in Overview when a task is settled in the list -->
+ <dimen name="task_thumbnail_splash_icon_size">52dp</dimen>
<!-- The border width shown when task is hovered -->
<dimen name="task_hover_border_width">4dp</dimen>
<!-- The space under the focused task icon -->
@@ -374,6 +376,7 @@
<dimen name="transient_taskbar_stash_spring_velocity_dp_per_s">400dp</dimen>
<dimen name="taskbar_tooltip_vertical_padding">8dp</dimen>
<dimen name="taskbar_tooltip_horizontal_padding">16dp</dimen>
+ <dimen name="taskbar_tooltip_y_offset">4dp</dimen>
<!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
<dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
@@ -434,6 +437,7 @@
<dimen name="bubblebar_stashed_handle_width">55dp</dimen>
<dimen name="bubblebar_stashed_size">@dimen/transient_taskbar_stashed_height</dimen>
<dimen name="bubblebar_stashed_handle_height">@dimen/taskbar_stashed_handle_height</dimen>
+ <dimen name="bubblebar_stashed_handle_spring_velocity_dp_per_s">@dimen/transient_taskbar_stash_spring_velocity_dp_per_s</dimen>
<!-- this is a pointer height minus 1dp to ensure the pointer overlaps with the bubblebar
background appropriately when close to the rounded corner -->
<dimen name="bubblebar_pointer_visible_size">9dp</dimen>
@@ -484,17 +488,22 @@
<!-- Keyboard Quick Switch -->
<dimen name="keyboard_quick_switch_border_width">4dp</dimen>
<dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_height">136dp</dimen>
<dimen name="keyboard_quick_switch_taskview_icon_size">52dp</dimen>
<dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
+ <dimen name="keyboard_quick_switch_desktop_icon_size">32dp</dimen>
<dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
<dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
<dimen name="keyboard_quick_switch_view_spacing">16dp</dimen>
- <dimen name="keyboard_quick_switch_split_view_spacing">2dp</dimen>
+ <dimen name="keyboard_quick_switch_view_small_spacing">4dp</dimen>
<dimen name="keyboard_quick_switch_view_radius">28dp</dimen>
<dimen name="keyboard_quick_switch_task_view_radius">16dp</dimen>
<dimen name="keyboard_quick_switch_no_recent_items_icon_size">24dp</dimen>
<dimen name="keyboard_quick_switch_no_recent_items_icon_margin">8dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_width">104dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_radius">360dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_horizontal_padding">16dp</dimen>
+ <dimen name="keyboard_quick_switch_text_button_fade_edge_length">20dp</dimen>
<!-- Digital Wellbeing -->
<dimen name="digital_wellbeing_toast_height">48dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 037a0f6..f72f3c5 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>
@@ -324,17 +327,14 @@
<!-- Label for moving drop target to the bottom or right side of the screen, depending on orientation (from the Taskbar only). -->
<string name="move_drop_target_bottom_or_right">Move to bottom/right</string>
- <!-- Label for quick switch tile showing how many more apps are available [CHAR LIMIT=NONE] -->
+ <!-- Label for quick switch tile showing how many more apps are available. The number will be displayed above this text. [CHAR LIMIT=NONE] -->
<string name="quick_switch_overflow">{count, plural,
- =1{Show # more app.}
- other{Show # more apps.}
+ =1{more app}
+ other{more apps}
}</string>
- <!-- Label for quick switch tile showing how many apps are available in desktop mode [CHAR LIMIT=NONE] -->
- <string name="quick_switch_desktop">{count, plural,
- =1{Show # desktop app.}
- other{Show # desktop apps.}
- }</string>
+ <!-- Label for quick switch tile to launch desktop mode [CHAR LIMIT=NONE] -->
+ <string name="quick_switch_desktop">Desktop</string>
<!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
<string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 1f4720c..c423d09 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -205,7 +205,7 @@
<item name="android:textColor">?attr/tutorialSubtitle</item>
</style>
- <style name="AllSetTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
+ <style name="AllSetTheme" parent="@style/DynamicColorsBaseLauncherTheme.NoActionBar">
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
@@ -272,10 +272,22 @@
<item name="lineHeight">20sp</item>
</style>
+ <style name="KeyboardQuickSwitchText.LargeText" parent="KeyboardQuickSwitchText">
+ <item name="android:textSize">32sp</item>
+ </style>
+
<style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
<item name="android:textColor">?attr/materialColorOnSurface</item>
</style>
+ <style name="KeyboardQuickSwitchText.OnTaskView" parent="KeyboardQuickSwitchText">
+ <item name="android:requiresFadingEdge">horizontal</item>
+ <item name="android:fadeScrollbars">false</item>
+ <item name="android:fadingEdgeLength">20dp</item>
+ <item name="android:ellipsize">none</item>
+ <item name="android:singleLine">true</item>
+ </style>
+
<style name="GestureTutorialActivity" parent="@style/AppTheme">
<item name="background">@android:color/transparent</item>
<item name="tutorialSubtitle">@android:color/black</item>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index d973149..a63ba0f 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -26,7 +26,7 @@
import android.animation.AnimatorSet;
import android.content.Context;
import android.os.Handler;
-import android.os.RemoteException;
+import android.util.Log;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationTarget;
@@ -196,6 +196,7 @@
if (skipFirstFrame) {
// Because t=0 has the app icon in its original spot, we can skip the
// first frame and have the same movement one frame earlier.
+ Log.d("b/311077782", "LauncherAnimationRunner.setAnimation");
mAnimator.setCurrentPlayTime(
Math.min(getSingleFrameMs(context), mAnimator.getTotalDuration()));
}
@@ -208,7 +209,7 @@
* animation finished runnable.
*/
@Override
- public void onAnimationFinished() throws RemoteException {
+ public void onAnimationFinished() {
mASyncFinishRunnable.run();
}
}
@@ -238,12 +239,5 @@
@Override
@UiThread
default void onAnimationCancelled() {}
-
- /**
- * Returns whether this animation factory supports a tightly coupled return animation.
- */
- default boolean supportsReturnTransition() {
- return false;
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
index 962fd91..1161720 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
@@ -15,10 +15,19 @@
*/
package com.android.launcher3;
+import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
+
import android.view.KeyEvent;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.LinearSmoothScroller;
+import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.allapps.AllAppsRecyclerView;
+import com.android.launcher3.allapps.SearchRecyclerView;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -26,14 +35,61 @@
import java.util.List;
public class QuickstepAccessibilityDelegate extends LauncherAccessibilityDelegate {
+ private QuickstepLauncher mLauncher;
public QuickstepAccessibilityDelegate(QuickstepLauncher launcher) {
super(launcher);
+ mLauncher = launcher;
mActions.put(PIN_PREDICTION, new LauncherAction(
PIN_PREDICTION, R.string.pin_prediction, KeyEvent.KEYCODE_P));
}
@Override
+ public void onPopulateAccessibilityEvent(View view, AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(view, event);
+ // Scroll to the position if focused view in main allapps list and not completely visible.
+ scrollToPositionIfNeeded(view);
+ }
+
+ private void scrollToPositionIfNeeded(View view) {
+ if (!Flags.accessibilityScrollOnAllapps()) {
+ return;
+ }
+ AllAppsRecyclerView contentView = mLauncher.getAppsView().getActiveRecyclerView();
+ if (contentView instanceof SearchRecyclerView) {
+ return;
+ }
+ LinearLayoutManager layoutManager = (LinearLayoutManager) contentView.getLayoutManager();
+ if (layoutManager == null) {
+ return;
+ }
+ RecyclerView.ViewHolder vh = contentView.findContainingViewHolder(view);
+ if (vh == null) {
+ return;
+ }
+ int itemPosition = vh.getBindingAdapterPosition();
+ if (itemPosition == NO_POSITION) {
+ return;
+ }
+ int firstCompletelyVisible = layoutManager.findFirstCompletelyVisibleItemPosition();
+ int lastCompletelyVisible = layoutManager.findLastCompletelyVisibleItemPosition();
+ boolean itemCompletelyVisible = firstCompletelyVisible <= itemPosition
+ && lastCompletelyVisible >= itemPosition;
+ if (itemCompletelyVisible) {
+ return;
+ }
+ RecyclerView.SmoothScroller smoothScroller =
+ new LinearSmoothScroller(mLauncher.asContext()) {
+ @Override
+ protected int getVerticalSnapPreference() {
+ return LinearSmoothScroller.SNAP_TO_ANY;
+ }
+ };
+ smoothScroller.setTargetPosition(itemPosition);
+ layoutManager.startSmoothScroll(smoothScroller);
+ }
+
+ @Override
protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
if (host instanceof PredictedAppIcon && !((PredictedAppIcon) host).isPinned()) {
out.add(new LauncherAction(PIN_PREDICTION, R.string.pin_prediction,
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index fe1b403..a64936d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -46,17 +46,12 @@
import static com.android.launcher3.Flags.enableContainerReturnAnimations;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.mapBoundToRange;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_BACK_SWIPE_HOME_ANIMATION;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
-import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
-import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -65,7 +60,6 @@
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.util.AnimUtils.clampToDuration;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
@@ -90,7 +84,6 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IBinder;
@@ -117,6 +110,7 @@
import android.view.animation.PathInterpolator;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
+import android.window.WindowAnimationState;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -139,16 +133,17 @@
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DynamicResource;
-import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.StableViewInfo;
import com.android.launcher3.views.FloatingIconView;
-import com.android.launcher3.views.ScrimView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.quickstep.LauncherBackAnimationController;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.util.AlreadyStartedBackAnimState;
+import com.android.quickstep.util.AnimatorBackState;
+import com.android.quickstep.util.BackAnimState;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig;
@@ -175,6 +170,7 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -183,9 +179,6 @@
*/
public class QuickstepTransitionManager implements OnDeviceProfileChangeListener {
- private static final String TRANSITION_COOKIE_PREFIX =
- "com.android.launcher3.QuickstepTransitionManager_activityLaunch";
-
private static final boolean ENABLE_SHELL_STARTING_SURFACE =
SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
@@ -259,7 +252,6 @@
// Strong refs to runners which are cleared when the launcher activity is destroyed
private RemoteAnimationFactory mWallpaperOpenRunner;
private RemoteAnimationFactory mAppLaunchRunner;
- private RemoteAnimationFactory mKeyguardGoingAwayRunner;
private RemoteAnimationFactory mWallpaperOpenTransitionRunner;
private RemoteTransition mLauncherOpenTransition;
@@ -328,7 +320,7 @@
* @return ActivityOptions with remote animations that controls how the window of the opening
* targets are displayed.
*/
- public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
+ public ActivityOptionsWrapper getActivityLaunchOptions(View v, ItemInfo itemInfo) {
boolean fromRecents = isLaunchingFromRecents(v, null /* targets */);
RunnableList onEndCallback = new RunnableList();
@@ -355,22 +347,7 @@
IRemoteCallback endCallback = completeRunnableListCallback(onEndCallback);
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);
-
- // Register the return animation so it can be triggered on back from the app to home.
- maybeRegisterAppReturnTransition(v);
-
+ options.setLaunchCookie(StableViewInfo.toLaunchCookie(itemInfo));
return new ActivityOptionsWrapper(options, onEndCallback);
}
@@ -383,21 +360,9 @@
ItemInfo tag = (ItemInfo) v.getTag();
ContainerAnimationRunner containerRunner = null;
if (tag != null && tag.shouldUseBackgroundAnimation()) {
- // The cookie should only override the default used by launcher if container return
- // animations are enabled.
- ActivityTransitionAnimator.TransitionCookie cookie =
- checkReturnAnimationsFlags()
- ? new ActivityTransitionAnimator.TransitionCookie(
- TRANSITION_COOKIE_PREFIX + tag.id)
- : null;
- ContainerAnimationRunner launchAnimationRunner =
- ContainerAnimationRunner.fromView(
- v, cookie, true /* forLaunch */, mLauncher, mStartingWindowListener,
- onEndCallback);
-
- if (launchAnimationRunner != null) {
- containerRunner = launchAnimationRunner;
- }
+ containerRunner = ContainerAnimationRunner.fromView(
+ v, true /* forLaunch */, mLauncher, mStartingWindowListener, onEndCallback,
+ null /* windowState */);
}
mAppLaunchRunner = containerRunner != null
@@ -407,51 +372,6 @@
}
/**
- * If container return animations are enabled and the current launch runner is itself a
- * {@link ContainerAnimationRunner}, registers a matching return animation that de-registers
- * itself after it has run once or is made obsolete by the view going away.
- */
- private void maybeRegisterAppReturnTransition(View v) {
- if (!checkReturnAnimationsFlags() || !mAppLaunchRunner.supportsReturnTransition()) {
- return;
- }
-
- ActivityTransitionAnimator.TransitionCookie cookie =
- ((ContainerAnimationRunner) mAppLaunchRunner).getCookie();
- RunnableList onEndCallback = new RunnableList();
- ContainerAnimationRunner runner =
- ContainerAnimationRunner.fromView(
- v, cookie, false /* forLaunch */, mLauncher, mStartingWindowListener,
- onEndCallback);
- RemoteTransition transition =
- new RemoteTransition(
- new LauncherAnimationRunner(
- mHandler, runner, true /* startAtFrontOfQueue */
- ).toRemoteTransition()
- );
-
- SystemUiProxy.INSTANCE.get(mLauncher).registerRemoteTransition(
- transition, ContainerAnimationRunner.buildBackToHomeFilter(cookie, mLauncher));
- ContainerAnimationRunner.setUpRemoteAnimationCleanup(
- v, transition, onEndCallback, mLauncher);
- }
-
- /**
- * Adds a new launch cookie for the activity launch if supported.
- * Prioritizes the explicitly provided cookie, falling back on extracting one from the given
- * {@link ItemInfo} if necessary.
- */
- private void addLaunchCookie(IBinder cookie, ItemInfo info, ActivityOptions options) {
- if (cookie == null) {
- cookie = mLauncher.getLaunchCookie(info);
- }
-
- if (cookie != null) {
- options.setLaunchCookie(cookie);
- }
- }
-
- /**
* Whether the launch is a recents app transition and we should do a launch animation
* from the recents view. Note that if the remote animation targets are not provided, this
* may not always be correct as we may resolve the opening app to a task when the animation
@@ -676,34 +596,11 @@
launcherAnimator.play(scaleAnim);
});
- final boolean scrimEnabled = ENABLE_SCRIM_FOR_APP_LAUNCH.get();
- if (scrimEnabled) {
- int scrimColor = Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
- int scrimColorTrans = ColorUtils.setAlphaComponent(scrimColor, 0);
- int[] colors = isAppOpening
- ? new int[]{scrimColorTrans, scrimColor}
- : new int[]{scrimColor, scrimColorTrans};
- ScrimView scrimView = mLauncher.getScrimView();
- if (scrimView.getBackground() instanceof ColorDrawable) {
- scrimView.setBackgroundColor(colors[0]);
-
- ObjectAnimator scrim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
- colors);
- scrim.setDuration(CONTENT_SCRIM_DURATION);
- scrim.setInterpolator(DECELERATE_1_5);
-
- launcherAnimator.play(scrim);
- }
- }
-
endListener = () -> {
viewsToAnimate.forEach(view -> {
SCALE_PROPERTY.set(view, 1f);
view.setLayerType(View.LAYER_TYPE_NONE, null);
});
- if (scrimEnabled) {
- mLauncher.getScrimView().setBackgroundColor(Color.TRANSPARENT);
- }
mLauncher.resumeExpensiveViewUpdates();
};
}
@@ -1212,38 +1109,25 @@
* additional animations.
*/
private void addRemoteAnimations(RemoteAnimationDefinition definition) {
- mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
+ mWallpaperOpenRunner = new WallpaperOpenLauncherAnimationRunner();
definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN,
WindowConfiguration.ACTIVITY_TYPE_STANDARD,
new RemoteAnimationAdapter(
new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
false /* startAtFrontOfQueue */),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
-
- if (KEYGUARD_ANIMATION.get()) {
- mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
- definition.addRemoteAnimation(
- WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
- new RemoteAnimationAdapter(
- new LauncherAnimationRunner(
- mHandler, mKeyguardGoingAwayRunner,
- true /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
- }
}
/**
* Registers remote animations used when closing apps to home screen.
*/
public void registerRemoteTransitions() {
- if (ENABLE_SHELL_TRANSITIONS) {
- SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
- mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */);
+ mWallpaperOpenTransitionRunner = new WallpaperOpenLauncherAnimationRunner();
mLauncherOpenTransition = new RemoteTransition(
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
false /* startAtFrontOfQueue */).toRemoteTransition(),
@@ -1298,13 +1182,10 @@
// definition so we don't have to wait for the system gc
mWallpaperOpenRunner = null;
mAppLaunchRunner = null;
- mKeyguardGoingAwayRunner = null;
}
protected void unregisterRemoteTransitions() {
- if (ENABLE_SHELL_TRANSITIONS) {
- SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
@@ -1358,41 +1239,6 @@
return false;
}
- /**
- * @return Runner that plays when user goes to Launcher
- * ie. pressing home, swiping up from nav bar.
- */
- RemoteAnimationFactory createWallpaperOpenRunner(boolean fromUnlock) {
- return new WallpaperOpenLauncherAnimationRunner(fromUnlock);
- }
-
- /**
- * Animator that controls the transformations of the windows when unlocking the device.
- */
- private Animator getUnlockWindowAnimator(RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets) {
- SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
- ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
- unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
- float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
- QuickStepContract.getWindowCornerRadius(mLauncher);
- unlockAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- SurfaceTransaction transaction = new SurfaceTransaction();
- for (int i = appTargets.length - 1; i >= 0; i--) {
- RemoteAnimationTarget target = appTargets[i];
- transaction.forSurface(target.leash)
- .setAlpha(1f)
- .setWindowCrop(target.screenSpaceBounds)
- .setCornerRadius(cornerRadius);
- }
- surfaceApplier.scheduleApply(transaction);
- }
- });
- return unlockAnimator;
- }
-
private static int getRotationChange(RemoteAnimationTarget[] appTargets) {
int rotationChange = 0;
for (RemoteAnimationTarget target : appTargets) {
@@ -1446,20 +1292,12 @@
// Find the associated item info for the launch cookie (if available), note that predicted
// apps actually have an id of -1, so use another default id here
- final ArrayList<IBinder> launchCookies = runningTaskTarget.taskInfo.launchCookies == null
- ? new ArrayList<>()
+ final List<IBinder> launchCookies = runningTaskTarget.taskInfo.launchCookies == null
+ ? Collections.EMPTY_LIST
: runningTaskTarget.taskInfo.launchCookies;
- int launchCookieItemId = NO_MATCHING_ID;
- for (IBinder cookie : launchCookies) {
- Integer itemId = ObjectWrapper.unwrap(cookie);
- if (itemId != null) {
- launchCookieItemId = itemId;
- break;
- }
- }
-
- return mLauncher.getFirstMatchForAppClose(launchCookieItemId, packageName,
+ return mLauncher.getFirstMatchForAppClose(
+ StableViewInfo.fromLaunchCookies(launchCookies), packageName,
UserHandle.of(runningTaskTarget.taskInfo.userId), true /* supportsAllAppsState */);
}
@@ -1711,20 +1549,48 @@
* Creates the {@link RectFSpringAnim} and {@link AnimatorSet} required to animate
* the transition.
*/
- public Pair<RectFSpringAnim, AnimatorSet> createWallpaperOpenAnimations(
+ @NonNull
+ public BackAnimState createWallpaperOpenAnimations(
RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets,
- boolean fromUnlock,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonAppTargets,
RectF startRect,
float startWindowCornerRadius,
boolean fromPredictiveBack) {
+ View launcherView = findLauncherView(appTargets);
+ if (checkReturnAnimationsFlags()
+ && launcherView != null
+ && launcherView.getTag() instanceof ItemInfo info
+ && info.shouldUseBackgroundAnimation()) {
+ // Try to create a return animation
+ RunnableList onEndCallback = new RunnableList();
+ WindowAnimationState windowState = new WindowAnimationState();
+ windowState.bounds = startRect;
+ windowState.bottomLeftRadius = windowState.bottomRightRadius =
+ windowState.topLeftRadius = windowState.topRightRadius =
+ startWindowCornerRadius;
+ ContainerAnimationRunner runner = ContainerAnimationRunner.fromView(
+ launcherView, false /* forLaunch */, mLauncher, mStartingWindowListener,
+ onEndCallback, windowState);
+ if (runner != null) {
+ runner.startAnimation(TRANSIT_CLOSE,
+ appTargets, wallpapers, nonAppTargets,
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() {
+ onEndCallback.executeAllAndDestroy();
+ }
+ });
+ return new AlreadyStartedBackAnimState(onEndCallback);
+ }
+ }
+
AnimatorSet anim = new AnimatorSet();
RectFSpringAnim rectFSpringAnim = null;
final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
|| launcherIsATargetWithMode(appTargets, MODE_OPENING);
- View launcherView = findLauncherView(appTargets);
boolean playFallBackAnimation = (launcherView == null
&& launcherIsForceInvisibleOrOpening)
|| mLauncher.getWorkspace().isOverlayShown()
@@ -1732,10 +1598,7 @@
boolean playWorkspaceReveal = !fromPredictiveBack;
boolean skipAllAppsScale = false;
- if (fromUnlock) {
- anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
- } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
- && !playFallBackAnimation) {
+ if (!playFallBackAnimation) {
PointF velocity;
if (enableScalingRevealHomeAnimation()) {
velocity = new PointF();
@@ -1827,7 +1690,7 @@
}
}
- return new Pair(rectFSpringAnim, anim);
+ return new AnimatorBackState(rectFSpringAnim, anim);
}
public static int getTaskbarToHomeDuration() {
@@ -1847,12 +1710,6 @@
*/
protected class WallpaperOpenLauncherAnimationRunner implements RemoteAnimationFactory {
- private final boolean mFromUnlock;
-
- public WallpaperOpenLauncherAnimationRunner(boolean fromUnlock) {
- mFromUnlock = fromUnlock;
- }
-
@Override
public void onAnimationStart(int transit,
RemoteAnimationTarget[] appTargets,
@@ -1883,14 +1740,14 @@
}
}
- Pair<RectFSpringAnim, AnimatorSet> pair = createWallpaperOpenAnimations(
- appTargets, wallpaperTargets, mFromUnlock, resolveRectF,
+ BackAnimState bankAnimState = createWallpaperOpenAnimations(
+ appTargets, wallpaperTargets, nonAppTargets, resolveRectF,
QuickStepContract.getWindowCornerRadius(mLauncher),
false /* fromPredictiveBack */);
TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, false, null);
mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
- result.setAnimation(pair.second, mLauncher);
+ bankAnimState.applyToAnimationResult(result, mLauncher);
}
}
@@ -1942,21 +1799,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);
}
@@ -1973,29 +1815,19 @@
/** The delegate runner that handles the actual animation. */
private final RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> mDelegate;
- @Nullable
- private final ActivityTransitionAnimator.TransitionCookie mCookie;
-
private ContainerAnimationRunner(
- RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate,
- ActivityTransitionAnimator.TransitionCookie cookie) {
+ RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate) {
mDelegate = delegate;
- mCookie = cookie;
- }
-
- @Nullable
- ActivityTransitionAnimator.TransitionCookie getCookie() {
- return mCookie;
}
@Nullable
static ContainerAnimationRunner fromView(
View v,
- ActivityTransitionAnimator.TransitionCookie cookie,
boolean forLaunch,
Launcher launcher,
StartingWindowListener startingWindowListener,
- RunnableList onEndCallback) {
+ RunnableList onEndCallback,
+ @Nullable WindowAnimationState windowState) {
if (!forLaunch && !checkReturnAnimationsFlags()) {
throw new IllegalStateException(
"forLaunch cannot be false when the enableContainerReturnAnimations or "
@@ -2005,7 +1837,7 @@
// First the controller is created. This is used by the runner to animate the
// origin/target view.
ActivityTransitionAnimator.Controller controller =
- buildController(v, cookie, forLaunch);
+ buildController(v, forLaunch, windowState);
if (controller == null) {
return null;
}
@@ -2030,8 +1862,7 @@
return new ContainerAnimationRunner(
new ActivityTransitionAnimator.AnimationDelegate(
- MAIN_EXECUTOR, controller, callback, listener),
- cookie);
+ MAIN_EXECUTOR, controller, callback, listener));
}
/**
@@ -2041,7 +1872,7 @@
*/
@Nullable
private static ActivityTransitionAnimator.Controller buildController(
- View v, ActivityTransitionAnimator.TransitionCookie cookie, boolean isLaunching) {
+ View v, boolean isLaunching, @Nullable WindowAnimationState windowState) {
View viewToUse = findLaunchableViewWithBackground(v);
if (viewToUse == null) {
return null;
@@ -2072,8 +1903,8 @@
@Nullable
@Override
- public ActivityTransitionAnimator.TransitionCookie getTransitionCookie() {
- return cookie;
+ public WindowAnimationState getWindowAnimatorState() {
+ return windowState;
}
};
}
@@ -2087,81 +1918,26 @@
View view) {
View current = view;
while (current.getBackground() == null || !(current instanceof LaunchableView)) {
- if (!(current.getParent() instanceof View)) {
+ if (current.getParent() instanceof View v) {
+ current = v;
+ } else {
return null;
}
-
- current = (View) current.getParent();
}
-
return (T) current;
}
- /**
- * Builds the filter used by WM Shell to match app closing transitions (only back, no home
- * button/gesture) to the given launch cookie.
- */
- static TransitionFilter buildBackToHomeFilter(
- ActivityTransitionAnimator.TransitionCookie cookie, Launcher launcher) {
- // Closing activity must include the cookie in its list of launch cookies.
- TransitionFilter.Requirement appRequirement = new TransitionFilter.Requirement();
- appRequirement.mActivityType = ACTIVITY_TYPE_STANDARD;
- appRequirement.mLaunchCookie = cookie;
- appRequirement.mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
- // Opening activity must be Launcher.
- TransitionFilter.Requirement launcherRequirement = new TransitionFilter.Requirement();
- launcherRequirement.mActivityType = ACTIVITY_TYPE_HOME;
- launcherRequirement.mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
- launcherRequirement.mTopActivity = launcher.getComponentName();
- // Transition types CLOSE and TO_BACK match the back button/gesture but not the home
- // button/gesture.
- TransitionFilter filter = new TransitionFilter();
- filter.mTypeSet = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
- filter.mRequirements =
- new TransitionFilter.Requirement[]{appRequirement, launcherRequirement};
- return filter;
- }
-
- /**
- * Creates various conditions to ensure that the given transition is cleaned up correctly
- * when necessary:
- * - if the transition has run, it is the callback that unregisters it;
- * - if the associated view is detached before the transition has had an opportunity to run,
- * a {@link View.OnAttachStateChangeListener} allows us to do the same (and removes
- * itself).
- */
- static void setUpRemoteAnimationCleanup(
- View v, RemoteTransition transition, RunnableList callback, Launcher launcher) {
- View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(@NonNull View v) {}
-
- @Override
- public void onViewDetachedFromWindow(@NonNull View v) {
- SystemUiProxy.INSTANCE.get(launcher)
- .unregisterRemoteTransition(transition);
- v.removeOnAttachStateChangeListener(this);
- }
- };
-
- // Remove the animation as soon as it has run once.
- callback.add(() -> {
- SystemUiProxy.INSTANCE.get(launcher).unregisterRemoteTransition(transition);
- if (v != null) {
- v.removeOnAttachStateChangeListener(listener);
- }
- });
-
- // Remove the animation when the view is detached from the hierarchy.
- // This is so that if back is not invoked (e.g. if we go back home through the home
- // gesture) we don't have obsolete transitions staying registered.
- v.addOnAttachStateChangeListener(listener);
- }
-
@Override
public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result) {
+ startAnimation(
+ transit, appTargets, wallpaperTargets, nonAppTargets, result);
+ }
+
+ public void startAnimation(int transit, RemoteAnimationTarget[] appTargets,
+ RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets,
+ IRemoteAnimationFinishedCallback result) {
mDelegate.onAnimationStart(
transit, appTargets, wallpaperTargets, nonAppTargets, result);
}
@@ -2170,11 +1946,6 @@
public void onAnimationCancelled() {
mDelegate.onAnimationCancelled();
}
-
- @Override
- public boolean supportsReturnTransition() {
- return true;
- }
}
/**
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index e925af6..955388d 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -20,7 +20,6 @@
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -42,6 +41,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.dragndrop.SimpleDragLayer;
+import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.WidgetPredictionsRequester;
import com.android.launcher3.model.WidgetsModel;
@@ -108,6 +108,7 @@
private SimpleDragLayer<WidgetPickerActivity> mDragLayer;
private WidgetsModel mModel;
private LauncherAppState mApp;
+ private StringCache mStringCache;
private WidgetPredictionsRequester mWidgetPredictionsRequester;
private final WidgetPickerDataProvider mWidgetPickerDataProvider =
new WidgetPickerDataProvider();
@@ -170,11 +171,6 @@
@Override
protected void registerBackDispatcher() {
- if (!enablePredictiveBackGesture()) {
- super.registerBackDispatcher();
- return;
- }
-
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
new BackAnimationCallback());
@@ -293,6 +289,11 @@
MODEL_EXECUTOR.execute(() -> {
LauncherAppState app = LauncherAppState.getInstance(this);
mModel.update(app, null);
+
+ StringCache stringCache = new StringCache();
+ stringCache.loadStrings(this);
+
+ bindStringCache(stringCache);
bindWidgets(mModel.getWidgetsByPackageItem());
// Open sheet once widgets are available, so that it doesn't interrupt the open
// animation.
@@ -305,6 +306,10 @@
});
}
+ private void bindStringCache(final StringCache stringCache) {
+ MAIN_EXECUTOR.execute(() -> mStringCache = stringCache);
+ }
+
private void bindWidgets(Map<PackageItemInfo, List<WidgetItem>> widgets) {
WidgetsListBaseEntriesBuilder builder = new WidgetsListBaseEntriesBuilder(
mApp.getContext());
@@ -342,6 +347,12 @@
}
}
+ @Nullable
+ @Override
+ public StringCache getStringCache() {
+ return mStringCache;
+ }
+
/**
* Animation callback for different predictive back animation states for the widget picker.
*/
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 9178062..f7da34a 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -30,7 +30,7 @@
import com.android.quickstep.SystemUiProxy
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.views.DesktopTaskView
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import java.util.function.Consumer
/** Manage recents related operations with desktop tasks */
@@ -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..f29980b 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -17,25 +17,31 @@
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
+import android.content.Context;
import android.os.Debug;
import android.util.Log;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.GestureState;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.fallback.RecentsState;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
@@ -47,8 +53,8 @@
private static final String TAG = "DesktopVisController";
private static final boolean DEBUG = false;
- private final Launcher mLauncher;
private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
+ private final Set<TaskbarDesktopModeListener> mTaskbarDesktopModeListeners = new HashSet<>();
private int mVisibleDesktopTasksCount;
private boolean mInOverviewState;
@@ -56,42 +62,46 @@
private boolean mGestureInProgress;
@Nullable
- private IDesktopTaskListener mDesktopTaskListener;
+ private DesktopTaskListenerImpl mDesktopTaskListener;
- public DesktopVisibilityController(Launcher launcher) {
- mLauncher = launcher;
+ @Nullable
+ private Context mContext;
+
+ public DesktopVisibilityController(@NonNull Context context) {
+ setContext(context);
}
- /**
- * 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);
- }
- });
- }
+ /** Sets the context and re-registers the System Ui listener */
+ private void setContext(@Nullable Context context) {
+ unregisterSystemUiListener();
+ mContext = context;
+ registerSystemUiListener();
+ }
- @Override
- public void onStashedChanged(int displayId, boolean stashed) {
- Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
- }
- };
- SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(mDesktopTaskListener);
+ /** Register a listener with System UI to receive updates about desktop tasks state */
+ private void registerSystemUiListener() {
+ if (mContext == null) {
+ return;
+ }
+ if (mDesktopTaskListener != null) {
+ return;
+ }
+ mDesktopTaskListener = new DesktopTaskListenerImpl(this, mContext.getDisplayId());
+ SystemUiProxy.INSTANCE.get(mContext).setDesktopTaskListener(mDesktopTaskListener);
}
/**
* Clear listener from System UI that was set with {@link #registerSystemUiListener()}
*/
- public void unregisterSystemUiListener() {
- SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(null);
+ private void unregisterSystemUiListener() {
+ if (mContext == null) {
+ return;
+ }
+ if (mDesktopTaskListener == null) {
+ return;
+ }
+ SystemUiProxy.INSTANCE.get(mContext).setDesktopTaskListener(null);
+ mDesktopTaskListener.release();
mDesktopTaskListener = null;
}
@@ -124,11 +134,24 @@
mDesktopVisibilityListeners.remove(listener);
}
+ /** Registers a listener for Taskbar changes in Desktop Mode. */
+ public void registerTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
+ mTaskbarDesktopModeListeners.add(listener);
+ }
+
+ /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */
+ public void unregisterTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
+ mTaskbarDesktopModeListeners.remove(listener);
+ }
+
/**
* Sets the number of desktop windows that are visible and updates launcher visibility based on
* it.
*/
public void setVisibleDesktopTasksCount(int visibleTasksCount) {
+ if (mContext == null) {
+ return;
+ }
if (DEBUG) {
Log.d(TAG, "setVisibleDesktopTasksCount: visibleTasksCount=" + visibleTasksCount
+ " currentValue=" + mVisibleDesktopTasksCount);
@@ -144,7 +167,7 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher) && wasVisible != isVisible) {
+ if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && wasVisible != isVisible) {
// TODO: b/333533253 - Remove after flag rollout
if (mVisibleDesktopTasksCount > 0) {
setLauncherViewsVisibility(View.INVISIBLE);
@@ -163,19 +186,33 @@
}
}
+ public void onLauncherStateChanged(LauncherState state) {
+ onLauncherStateChanged(
+ state, state == LauncherState.BACKGROUND_APP, state.isRecentsViewVisible);
+ }
+
+ public void onLauncherStateChanged(RecentsState state) {
+ onLauncherStateChanged(
+ state, state == RecentsState.BACKGROUND_APP, state.isRecentsViewVisible());
+ }
+
/**
* Process launcher state change and update launcher view visibility based on desktop state
*/
- public void onLauncherStateChanged(LauncherState state) {
+ public void onLauncherStateChanged(
+ BaseState<?> state, boolean isBackgroundAppState, boolean isRecentsViewVisible) {
if (DEBUG) {
Log.d(TAG, "onLauncherStateChanged: newState=" + state);
}
- setBackgroundStateEnabled(state == BACKGROUND_APP);
+ setBackgroundStateEnabled(isBackgroundAppState);
// Desktop visibility tracks overview and background state separately
- setOverviewStateEnabled(state != BACKGROUND_APP && state.isRecentsViewVisible);
+ setOverviewStateEnabled(!isBackgroundAppState && isRecentsViewVisible);
}
private void setOverviewStateEnabled(boolean overviewStateEnabled) {
+ if (mContext == null) {
+ return;
+ }
if (DEBUG) {
Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled
+ " currentValue=" + mInOverviewState);
@@ -188,7 +225,7 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
+ if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
return;
}
// TODO: b/333533253 - Clean up after flag rollout
@@ -206,13 +243,26 @@
}
private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) {
+ if (mContext == null) {
+ return;
+ }
if (DEBUG) {
Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible);
}
for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
}
- DisplayController.handleInfoChangeForDesktopMode(mLauncher);
+ DisplayController.handleInfoChangeForDesktopMode(mContext);
+ }
+
+ private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTaskbarDesktopModeListeners: doesAnyTaskRequireTaskbarRounding="
+ + doesAnyTaskRequireTaskbarRounding);
+ }
+ for (TaskbarDesktopModeListener listener : mTaskbarDesktopModeListeners) {
+ listener.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding);
+ }
}
/**
@@ -288,22 +338,32 @@
* TODO: b/333533253 - Remove after flag rollout
*/
private void setLauncherViewsVisibility(int visibility) {
- if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
+ if (mContext == null) {
+ return;
+ }
+ if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
return;
}
if (DEBUG) {
Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility + " "
+ Debug.getCaller());
}
- View workspaceView = mLauncher.getWorkspace();
- if (workspaceView != null) {
- workspaceView.setVisibility(visibility);
+ if (!(mContext instanceof ActivityContext activity)) {
+ return;
}
- View dragLayer = mLauncher.getDragLayer();
+ View dragLayer = activity.getDragLayer();
if (dragLayer != null) {
dragLayer.setVisibility(visibility);
}
- if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null
+ if (!(activity instanceof Launcher launcher)) {
+ return;
+ }
+ View workspaceView = launcher.getWorkspace();
+ if (workspaceView != null) {
+ workspaceView.setVisibility(visibility);
+ }
+ if (launcher instanceof QuickstepLauncher ql
+ && ql.getTaskbarUIController() != null
&& mVisibleDesktopTasksCount != 0) {
ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE);
}
@@ -313,7 +373,10 @@
* TODO: b/333533253 - Remove after flag rollout
*/
private void markLauncherPaused() {
- if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
+ if (mContext == null) {
+ return;
+ }
+ if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
return;
}
if (DEBUG) {
@@ -330,7 +393,10 @@
* TODO: b/333533253 - Remove after flag rollout
*/
private void markLauncherResumed() {
- if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
+ if (mContext == null) {
+ return;
+ }
+ if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
return;
}
if (DEBUG) {
@@ -346,6 +412,22 @@
}
}
+ public void onDestroy() {
+ setContext(null);
+ }
+
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "DesktopVisibilityController:");
+
+ pw.println(prefix + "\tmDesktopVisibilityListeners=" + mDesktopVisibilityListeners);
+ pw.println(prefix + "\tmVisibleDesktopTasksCount=" + mVisibleDesktopTasksCount);
+ pw.println(prefix + "\tmInOverviewState=" + mInOverviewState);
+ pw.println(prefix + "\tmBackgroundStateEnabled=" + mBackgroundStateEnabled);
+ pw.println(prefix + "\tmGestureInProgress=" + mGestureInProgress);
+ pw.println(prefix + "\tmDesktopTaskListener=" + mDesktopTaskListener);
+ pw.println(prefix + "\tmContext=" + mContext);
+ }
+
/** A listener for when the user enters/exits Desktop Mode. */
public interface DesktopVisibilityListener {
/**
@@ -355,4 +437,65 @@
*/
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, "DesktopTaskListenerImpl: onStashedChanged is deprecated");
+ }
+
+ @Override
+ public void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding) {
+ MAIN_EXECUTOR.execute(() -> {
+ if (mController != null && DesktopModeStatus.useRoundedCorners()) {
+ Log.d(TAG, "DesktopTaskListenerImpl: doesAnyTaskRequireTaskbarRounding= "
+ + doesAnyTaskRequireTaskbarRounding);
+ mController.notifyTaskbarDesktopModeListeners(
+ doesAnyTaskRequireTaskbarRounding);
+ }
+ });
+ }
+ }
+
+ /** A listener for Taskbar in Desktop Mode. */
+ public interface TaskbarDesktopModeListener {
+ /**
+ * Callback for when task is resized in desktop mode.
+ *
+ * @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness.
+ */
+ void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding);
+ }
}
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/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 06d9ee6..929e793 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -70,7 +70,6 @@
@Override
protected void init(TaskbarControllers taskbarControllers) {
super.init(taskbarControllers);
-
mRecentsActivity.setTaskbarUIController(this);
mRecentsActivity.getStateManager().addStateListener(mStateListener);
}
@@ -78,6 +77,7 @@
@Override
protected void onDestroy() {
super.onDestroy();
+ getRecentsView().setTaskLaunchListener(null);
mRecentsActivity.setTaskbarUIController(null);
mRecentsActivity.getStateManager().removeStateListener(mStateListener);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 46501c4..ea432f3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -23,12 +23,11 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
-import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.LayoutUtils;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -66,6 +65,9 @@
@Nullable private KeyboardQuickSwitchViewController mQuickSwitchViewController;
+ private boolean mHasDesktopTask = false;
+ private boolean mWasDesktopTaskFilteredOut = false;
+
/** Initialize the controller. */
public void init(@NonNull TaskbarControllers controllers) {
mControllers = controllers;
@@ -112,10 +114,8 @@
mQuickSwitchViewController = new KeyboardQuickSwitchViewController(
mControllers, overlayContext, keyboardQuickSwitchView, mControllerCallbacks);
- DesktopVisibilityController desktopController =
- LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
final boolean onDesktop =
- desktopController != null && desktopController.areDesktopTasksVisible();
+ mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible();
if (mModel.isTaskListValid(mTaskListChangeId)) {
// When we are opening the KQS with no focus override, check if the first task is
@@ -126,11 +126,15 @@
/* updateTasks= */ false,
currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
? 0 : currentFocusedIndex,
- onDesktop);
+ onDesktop,
+ mHasDesktopTask,
+ mWasDesktopTaskFilteredOut);
return;
}
mTaskListChangeId = mModel.getTasks((tasks) -> {
+ mHasDesktopTask = false;
+ mWasDesktopTaskFilteredOut = false;
if (onDesktop) {
processLoadedTasksOnDesktop(tasks);
} else {
@@ -144,7 +148,9 @@
/* updateTasks= */ true,
currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
? 0 : currentFocusedIndex,
- onDesktop);
+ onDesktop,
+ mHasDesktopTask,
+ mWasDesktopTaskFilteredOut);
});
}
@@ -152,9 +158,22 @@
// Only store MAX_TASK tasks, from most to least recent
Collections.reverse(tasks);
mTasks = tasks.stream()
+ .filter(task -> !(task instanceof DesktopTask))
.limit(MAX_TASKS)
.collect(Collectors.toList());
- mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
+
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i) instanceof DesktopTask) {
+ mHasDesktopTask = true;
+ if (i < mTasks.size()) {
+ mWasDesktopTaskFilteredOut = true;
+ }
+ break;
+ }
+ }
+
+ mNumHiddenTasks = Math.max(0,
+ tasks.size() - (mWasDesktopTaskFilteredOut ? 1 : 0) - MAX_TASKS);
}
private void processLoadedTasksOnDesktop(List<GroupTask> tasks) {
@@ -214,6 +233,8 @@
pw.println(prefix + "\tisOpen=" + (mQuickSwitchViewController != null));
pw.println(prefix + "\tmNumHiddenTasks=" + mNumHiddenTasks);
pw.println(prefix + "\tmTaskListChangeId=" + mTaskListChangeId);
+ pw.println(prefix + "\tmHasDesktopTask=" + mHasDesktopTask);
+ pw.println(prefix + "\tmWasDesktopTaskFilteredOut=" + mWasDesktopTaskFilteredOut);
pw.println(prefix + "\tmTasks=[");
for (GroupTask task : mTasks) {
Task task1 = task.task1;
@@ -235,10 +256,6 @@
class ControllerCallbacks {
- int getTaskCount() {
- return mTasks.size() + (mNumHiddenTasks == 0 ? 0 : 1);
- }
-
@Nullable
GroupTask getTaskAt(int index) {
return index < 0 || index >= mTasks.size() ? null : mTasks.get(index);
@@ -279,5 +296,10 @@
boolean isFirstTaskRunning() {
return isTaskRunning(getTaskAt(0));
}
+
+ boolean isAspectRatioSquare() {
+ return mControllers != null && LayoutUtils.isAspectRatioSquare(
+ mControllers.taskbarActivityContext.getDeviceProfile().aspectRatio);
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index 39b4f77..ce96556 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -36,22 +36,25 @@
import com.android.launcher3.R;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
import com.android.quickstep.util.BorderAnimator;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import java.util.function.Consumer;
-
import kotlin.Unit;
+import java.util.function.Consumer;
+
/**
* A view that displays a recent task during a keyboard quick switch.
*/
public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
private static final float THUMBNAIL_BLUR_RADIUS = 1f;
+ private static final int INVALID_BORDER_RADIUS = -1;
@ColorInt private final int mBorderColor;
+ @ColorInt private final int mBorderRadius;
@Nullable private BorderAnimator mBorderAnimator;
@@ -87,6 +90,8 @@
mBorderColor = ta.getColor(
R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR);
+ mBorderRadius = ta.getDimensionPixelSize(
+ R.styleable.TaskView_focusBorderRadius, INVALID_BORDER_RADIUS);
ta.recycle();
}
@@ -103,8 +108,10 @@
Preconditions.assertNotNull(mContent);
mBorderAnimator = BorderAnimator.createScalingBorderAnimator(
- /* borderRadiusPx= */ resources.getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_task_view_radius),
+ /* borderRadiusPx= */ mBorderRadius != INVALID_BORDER_RADIUS
+ ? mBorderRadius
+ : resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_task_view_radius),
/* borderWidthPx= */ resources.getDimensionPixelSize(
R.dimen.keyboard_quick_switch_border_width),
/* boundsBuilder= */ bounds -> {
@@ -167,6 +174,61 @@
});
}
+ protected void setThumbnailsForSplitTasks(
+ @NonNull Task task1,
+ @Nullable Task task2,
+ @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction,
+ @Nullable IconUpdateFunction iconUpdateFunction,
+ @Nullable SplitBounds splitBounds) {
+ setThumbnails(task1, task2, thumbnailUpdateFunction, iconUpdateFunction);
+
+ if (splitBounds == null) {
+ return;
+ }
+
+
+ final boolean isLeftRightSplit = !splitBounds.appsStackedVertically;
+ final float leftOrTopTaskPercent = isLeftRightSplit
+ ? splitBounds.leftTaskPercent : splitBounds.topTaskPercent;
+
+ ConstraintLayout.LayoutParams leftTopParams = (ConstraintLayout.LayoutParams)
+ mThumbnailView1.getLayoutParams();
+ ConstraintLayout.LayoutParams rightBottomParams = (ConstraintLayout.LayoutParams)
+ mThumbnailView2.getLayoutParams();
+
+ if (isLeftRightSplit) {
+ // Set thumbnail view ratio in left right split mode.
+ leftTopParams.width = 0; // Set width to 0dp, so it uses the constraint dimension ratio.
+ leftTopParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT;
+ leftTopParams.matchConstraintPercentWidth = leftOrTopTaskPercent;
+ leftTopParams.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
+ leftTopParams.rightToLeft = R.id.thumbnail_2;
+ mThumbnailView1.setLayoutParams(leftTopParams);
+
+ rightBottomParams.width = 0;
+ rightBottomParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT;
+ rightBottomParams.matchConstraintPercentWidth = 1 - leftOrTopTaskPercent;
+ rightBottomParams.leftToRight = R.id.thumbnail_1;
+ rightBottomParams.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID;
+ mThumbnailView2.setLayoutParams(rightBottomParams);
+ } else {
+ // Set thumbnail view ratio in top bottom split mode.
+ leftTopParams.height = 0;
+ leftTopParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT;
+ leftTopParams.matchConstraintPercentHeight = leftOrTopTaskPercent;
+ leftTopParams.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
+ leftTopParams.bottomToTop = R.id.thumbnail_2;
+ mThumbnailView1.setLayoutParams(leftTopParams);
+
+ rightBottomParams.height = 0;
+ rightBottomParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT;
+ rightBottomParams.matchConstraintPercentHeight = 1 - leftOrTopTaskPercent;
+ rightBottomParams.topToBottom = R.id.thumbnail_1;
+ rightBottomParams.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID;
+ mThumbnailView2.setLayoutParams(rightBottomParams);
+ }
+ }
+
private void applyThumbnail(
@Nullable ImageView thumbnailView,
@Nullable Task task,
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 0ba5de1..b4102a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -36,14 +36,12 @@
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import android.widget.HorizontalScrollView;
-import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.core.content.res.ResourcesCompat;
import com.android.app.animation.Interpolators;
import com.android.internal.jank.Cuj;
@@ -52,7 +50,6 @@
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -101,9 +98,13 @@
private int mTaskViewWidth;
private int mTaskViewHeight;
private int mSpacing;
+ private int mSmallSpacing;
private int mOutlineRadius;
private boolean mIsRtl;
+ private int mOverviewTaskIndex = -1;
+ private int mDesktopTaskIndex = -1;
+
@Nullable private AnimatorSet mOpenAnimation;
@Nullable private KeyboardQuickSwitchViewController.ViewCallbacks mViewCallbacks;
@@ -140,6 +141,8 @@
mTaskViewHeight = resources.getDimensionPixelSize(
R.dimen.keyboard_quick_switch_taskview_height);
mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
+ mSmallSpacing = resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_view_small_spacing);
mOutlineRadius = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_radius);
mIsRtl = Utilities.isRtl(resources);
}
@@ -147,6 +150,7 @@
private KeyboardQuickSwitchTaskView createAndAddTaskView(
int index,
boolean isFinalView,
+ boolean useSmallStartSpacing,
@LayoutRes int resId,
@NonNull LayoutInflater layoutInflater,
@Nullable View previousView) {
@@ -155,7 +159,7 @@
taskView.setId(View.generateViewId());
taskView.setOnClickListener(v -> mViewCallbacks.launchTaskAt(index));
- LayoutParams lp = new LayoutParams(mTaskViewWidth, mTaskViewHeight);
+ LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// Create a left-to-right ordering of views (or right-to-left in RTL locales)
if (previousView != null) {
lp.startToEnd = previousView.getId();
@@ -165,7 +169,7 @@
lp.topToTop = PARENT_ID;
lp.bottomToBottom = PARENT_ID;
// Add spacing between views
- lp.setMarginStart(mSpacing);
+ lp.setMarginStart(useSmallStartSpacing ? mSmallSpacing : mSpacing);
if (isFinalView) {
// Add spacing to the end of the final view so that scrolling ends with some padding.
lp.endToEnd = PARENT_ID;
@@ -184,7 +188,8 @@
int numHiddenTasks,
boolean updateTasks,
int currentFocusIndexOverride,
- @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
+ @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks,
+ boolean useDesktopTaskView) {
mViewCallbacks = viewCallbacks;
Resources resources = context.getResources();
Resources.Theme theme = context.getTheme();
@@ -196,50 +201,64 @@
GroupTask groupTask = groupTasks.get(i);
KeyboardQuickSwitchTaskView currentTaskView = createAndAddTaskView(
i,
- /* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
- groupTask instanceof DesktopTask
- ? R.layout.keyboard_quick_switch_textonly_taskview
+ /* isFinalView= */ i == tasksToDisplay - 1
+ && numHiddenTasks == 0 && !useDesktopTaskView,
+ /* useSmallStartSpacing= */ false,
+ mViewCallbacks.isAspectRatioSquare()
+ ? R.layout.keyboard_quick_switch_taskview_square
: R.layout.keyboard_quick_switch_taskview,
layoutInflater,
previousTaskView);
- if (groupTask instanceof DesktopTask desktopTask) {
- HashMap<String, Integer> args = new HashMap<>();
- args.put("count", desktopTask.tasks.size());
+ final boolean firstTaskIsLeftTopTask =
+ groupTask.mSplitBounds == null
+ || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id
+ || groupTask.task2 == null;
- currentTaskView.<ImageView>findViewById(R.id.icon).setImageDrawable(
- ResourcesCompat.getDrawable(resources, R.drawable.ic_desktop, theme));
- currentTaskView.<TextView>findViewById(R.id.text).setText(new MessageFormat(
- resources.getString(R.string.quick_switch_desktop),
- Locale.getDefault()).format(args));
- } else {
- currentTaskView.setThumbnails(
- groupTask.task1,
- groupTask.task2,
- updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
- updateTasks ? mViewCallbacks::updateIconInBackground : null);
- }
+ currentTaskView.setThumbnailsForSplitTasks(
+ firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2,
+ firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1,
+ updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+ updateTasks ? mViewCallbacks::updateIconInBackground : null,
+ groupTask.mSplitBounds);
+
previousTaskView = currentTaskView;
}
-
if (numHiddenTasks > 0) {
HashMap<String, Integer> args = new HashMap<>();
args.put("count", numHiddenTasks);
+ mOverviewTaskIndex = getTaskCount();
View overviewButton = createAndAddTaskView(
- MAX_TASKS,
- /* isFinalView= */ true,
- R.layout.keyboard_quick_switch_textonly_taskview,
+ mOverviewTaskIndex,
+ /* isFinalView= */ !useDesktopTaskView,
+ /* useSmallStartSpacing= */ false,
+ R.layout.keyboard_quick_switch_overview_taskview,
layoutInflater,
previousTaskView);
- overviewButton.<ImageView>findViewById(R.id.icon).setImageDrawable(
- ResourcesCompat.getDrawable(resources, R.drawable.view_carousel, theme));
- overviewButton.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+ overviewButton.<TextView>findViewById(R.id.large_text).setText(
+ String.format(Locale.getDefault(), "%d", numHiddenTasks));
+ overviewButton.<TextView>findViewById(R.id.small_text).setText(new MessageFormat(
resources.getString(R.string.quick_switch_overflow),
Locale.getDefault()).format(args));
+
+ previousTaskView = overviewButton;
}
- mDisplayingRecentTasks = !groupTasks.isEmpty();
+ if (useDesktopTaskView) {
+ mDesktopTaskIndex = getTaskCount();
+ View desktopButton = createAndAddTaskView(
+ mDesktopTaskIndex,
+ /* isFinalView= */ true,
+ /* useSmallStartSpacing= */ numHiddenTasks > 0,
+ R.layout.keyboard_quick_switch_desktop_taskview,
+ layoutInflater,
+ previousTaskView);
+
+ desktopButton.<TextView>findViewById(R.id.text).setText(
+ resources.getString(R.string.quick_switch_desktop));
+ }
+ mDisplayingRecentTasks = !groupTasks.isEmpty() || useDesktopTaskView;
getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@@ -252,6 +271,14 @@
});
}
+ int getOverviewTaskIndex() {
+ return mOverviewTaskIndex;
+ }
+
+ int getDesktopTaskIndex() {
+ return mDesktopTaskIndex;
+ }
+
protected Animator getCloseAnimation() {
AnimatorSet closeAnimation = new AnimatorSet();
@@ -362,7 +389,7 @@
}
});
animateFocusMove(-1, Math.min(
- mContent.getChildCount() - 1,
+ getTaskCount() - 1,
currentFocusIndexOverride == -1 ? 1 : currentFocusIndexOverride));
displayedContent.setVisibility(VISIBLE);
setVisibility(VISIBLE);
@@ -569,7 +596,11 @@
@Nullable
protected KeyboardQuickSwitchTaskView getTaskAt(int index) {
- return !mDisplayingRecentTasks || index < 0 || index >= mContent.getChildCount()
+ return !mDisplayingRecentTasks || index < 0 || index >= getTaskCount()
? null : (KeyboardQuickSwitchTaskView) mContent.getChildAt(index);
}
+
+ public int getTaskCount() {
+ return mContent.getChildCount();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index d411ba6..40e77e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.KeyEvent;
@@ -28,6 +30,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SlideInRemoteTransition;
import com.android.systemui.shared.recents.model.Task;
@@ -56,6 +59,7 @@
private int mCurrentFocusIndex = -1;
private boolean mOnDesktop;
+ private boolean mWasDesktopTaskFilteredOut;
protected KeyboardQuickSwitchViewController(
@NonNull TaskbarControllers controllers,
@@ -77,9 +81,12 @@
int numHiddenTasks,
boolean updateTasks,
int currentFocusIndexOverride,
- boolean onDesktop) {
+ boolean onDesktop,
+ boolean hasDesktopTask,
+ boolean wasDesktopTaskFilteredOut) {
mOverlayContext.getDragLayer().addView(mKeyboardQuickSwitchView);
mOnDesktop = onDesktop;
+ mWasDesktopTaskFilteredOut = wasDesktopTaskFilteredOut;
mKeyboardQuickSwitchView.applyLoadPlan(
mOverlayContext,
@@ -87,7 +94,8 @@
numHiddenTasks,
updateTasks,
currentFocusIndexOverride,
- mViewCallbacks);
+ mViewCallbacks,
+ /* useDesktopTaskView= */ !onDesktop && hasDesktopTask);
}
boolean isCloseAnimationRunning() {
@@ -136,7 +144,7 @@
}
// If the user quick switches too quickly, updateCurrentFocusIndex might not have run.
return launchTaskAt(mControllerCallbacks.isFirstTaskRunning()
- && mControllerCallbacks.getTaskCount() > 1 ? 1 : 0);
+ && mKeyboardQuickSwitchView.getTaskCount() > 1 ? 1 : 0);
}
private int launchTaskAt(int index) {
@@ -144,17 +152,11 @@
// Ignore taps on task views and alt key unpresses while the close animation is running.
return -1;
}
- // Even with a valid index, this can be null if the user tries to quick switch before the
- // views have been added in the KeyboardQuickSwitchView.
- GroupTask task = mControllerCallbacks.getTaskAt(index);
- if (task == null) {
- return mOnDesktop ? 1 : Math.max(0, index);
+ if (index == mKeyboardQuickSwitchView.getOverviewTaskIndex()) {
+ // If there is a desktop task view, then we should account for it when focusing the
+ // first hidden non-desktop task view in recents view
+ return mOnDesktop ? 1 : (mWasDesktopTaskFilteredOut ? index + 1 : index);
}
- if (mControllerCallbacks.isTaskRunning(task)) {
- // Ignore attempts to run the selected task if it is already running.
- return -1;
- }
-
Runnable onStartCallback = () -> InteractionJankMonitorWrapper.begin(
mKeyboardQuickSwitchView, Cuj.CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH);
Runnable onFinishCallback = () -> InteractionJankMonitorWrapper.end(
@@ -169,6 +171,24 @@
onStartCallback,
onFinishCallback),
"SlideInTransition");
+ if (index == mKeyboardQuickSwitchView.getDesktopTaskIndex()) {
+ UI_HELPER_EXECUTOR.execute(() ->
+ SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
+ .showDesktopApps(
+ mKeyboardQuickSwitchView.getDisplay().getDisplayId(),
+ remoteTransition));
+ return -1;
+ }
+ // Even with a valid index, this can be null if the user tries to quick switch before the
+ // views have been added in the KeyboardQuickSwitchView.
+ GroupTask task = mControllerCallbacks.getTaskAt(index);
+ if (task == null) {
+ return mOnDesktop ? 1 : Math.max(0, index);
+ }
+ if (mControllerCallbacks.isTaskRunning(task)) {
+ // Ignore attempts to run the selected task if it is already running.
+ return -1;
+ }
mControllers.taskbarActivityContext.handleGroupTaskLaunch(
task,
remoteTransition,
@@ -195,6 +215,8 @@
pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
pw.println(prefix + "\tisCloseAnimationRunning=" + isCloseAnimationRunning());
pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
+ pw.println(prefix + "\tmOnDesktop=" + mOnDesktop);
+ pw.println(prefix + "\tmWasDesktopTaskFilteredOut=" + mWasDesktopTaskFilteredOut);
}
class ViewCallbacks {
@@ -222,7 +244,7 @@
boolean traverseBackwards = (keyCode == KeyEvent.KEYCODE_TAB && event.isShiftPressed())
|| (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && isRTL)
|| (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && !isRTL);
- int taskCount = mControllerCallbacks.getTaskCount();
+ int taskCount = mKeyboardQuickSwitchView.getTaskCount();
int toIndex = mCurrentFocusIndex == -1
// Focus the second-most recent app if possible
? (taskCount > 1 ? 1 : 0)
@@ -257,5 +279,9 @@
void updateIconInBackground(Task task, Consumer<Task> callback) {
mControllerCallbacks.updateIconInBackground(task, callback);
}
+
+ boolean isAspectRatioSquare() {
+ return mControllerCallbacks.isAspectRatioSquare();
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 3981e43..5513599 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -19,8 +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;
import android.animation.Animator;
@@ -40,14 +38,12 @@
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.HomeVisibilityState;
-import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
@@ -130,8 +126,8 @@
@Override
protected void onDestroy() {
- super.onDestroy();
onLauncherVisibilityChanged(false);
+ super.onDestroy();
mTaskbarLauncherStateController.onDestroy();
mLauncher.setTaskbarUIController(null);
@@ -139,6 +135,11 @@
mHomeState.removeListener(mVisibilityChangeListener);
}
+ /** Returns {@code true} if launcher is currently presenting the home screen. */
+ public boolean isOnHome() {
+ return mTaskbarLauncherStateController.isOnHome();
+ }
+
private void onInAppDisplayProgressChanged() {
if (mControllers != null) {
// Update our shared state so we can restore it if taskbar gets recreated.
@@ -225,23 +226,21 @@
// 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 (isVisible && (nonInteractiveState || mSkipLauncherVisibilityChange)) {
return null;
}
- DesktopVisibilityController desktopController =
- LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher)
- && desktopController != null
- && desktopController.areDesktopTasksVisible()) {
+ && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
// TODO: b/333533253 - Remove after flag rollout
isVisible = false;
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
- if (fromInit) {
+ if (fromInit || mControllers == null) {
duration = 0;
}
return mTaskbarLauncherStateController.applyState(duration, startAnimation);
@@ -276,35 +275,18 @@
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();
}
public boolean isDraggingItem() {
- return mControllers.taskbarDragController.isDragging();
+ boolean bubblesDragging = false;
+ if (mControllers.bubbleControllers.isPresent()) {
+ bubblesDragging =
+ mControllers.bubbleControllers.get().bubbleDragController.isDragging();
+ }
+ return mControllers.taskbarDragController.isDragging() || bubblesDragging;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 7338485..a979d58 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -63,7 +63,6 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Region.Op;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.graphics.drawable.RotateDrawable;
@@ -74,8 +73,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
-import android.view.View.OnClickListener;
-import android.view.View.OnHoverListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
@@ -106,7 +103,6 @@
import com.android.systemui.shared.navigationbar.KeyButtonRipple;
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton;
-import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -267,7 +263,7 @@
int setupSize = mControllers.taskbarActivityContext.getSetupWindowSize();
Point p = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
- mContext.isPhoneMode());
+ mContext.isPhoneMode(), mContext.isGestureNav());
ViewGroup.LayoutParams navButtonsViewLayoutParams = mNavButtonsView.getLayoutParams();
navButtonsViewLayoutParams.width = p.x;
if (!mContext.isUserSetupComplete()) {
@@ -304,8 +300,13 @@
.get(ALPHA_INDEX_SMALL_SCREEN),
flags -> (flags & FLAG_SMALL_SCREEN) == 0));
- mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
- .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+ if (!mContext.isPhoneMode()) {
+ mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
+ .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+ }
+
+ // Start at 1 because relevant flags are unset at init.
+ mOnBackgroundNavButtonColorOverrideMultiplier.value = 1;
// Force nav buttons (specifically back button) to be visible during setup wizard.
boolean isInSetup = !mContext.isUserSetupComplete();
@@ -317,39 +318,41 @@
// - IME is showing (add separate translation for IME)
// - VoiceInteractionWindow (assistant) is showing
// - Keyboard shortcuts helper is showing
- int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
- | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
- mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
- flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
- 1, 0));
- // Center nav buttons in new height for IME.
- float transForIme = (mContext.getDeviceProfile().taskbarHeight
- - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
- // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
- float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
- mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
- flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
- transForIme, defaultButtonTransY));
+ if (!mContext.isPhoneMode()) {
+ int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
+ | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
+ mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
+ flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
+ 1, 0));
+ // Center nav buttons in new height for IME.
+ float transForIme = (mContext.getDeviceProfile().taskbarHeight
+ - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
+ // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
+ float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
+ mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
+ transForIme, defaultButtonTransY));
- // Start at 1 because relevant flags are unset at init.
- mOnBackgroundNavButtonColorOverrideMultiplier.value = 1;
- mPropertyHolders.add(new StatePropertyHolder(
- mOnBackgroundNavButtonColorOverrideMultiplier,
- flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
+ mPropertyHolders.add(new StatePropertyHolder(
+ mOnBackgroundNavButtonColorOverrideMultiplier,
+ flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
- mPropertyHolders.add(new StatePropertyHolder(
- mSlideInViewVisibleNavButtonColorOverride,
- flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+ mPropertyHolders.add(new StatePropertyHolder(
+ mSlideInViewVisibleNavButtonColorOverride,
+ flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+ }
if (alwaysShowButtons) {
initButtons(mNavButtonContainer, mEndContextualContainer,
mControllers.navButtonController);
updateButtonLayoutSpacing();
- updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneButtonNavMode());
+ updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneMode());
- mPropertyHolders.add(new StatePropertyHolder(
- mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
- flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
+ if (!mContext.isPhoneMode()) {
+ mPropertyHolders.add(new StatePropertyHolder(
+ mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
+ flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
+ }
} else if (!mIsImeRenderingNavButtons) {
View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
mStartContextualContainer, mControllers.navButtonController, R.id.back);
@@ -711,7 +714,7 @@
private void applyState() {
int count = mPropertyHolders.size();
for (int i = 0; i < count; i++) {
- mPropertyHolders.get(i).setState(mState);
+ mPropertyHolders.get(i).setState(mState, mContext.isGestureNav());
}
}
@@ -1177,83 +1180,6 @@
}
}
- private class RotationButtonImpl implements RotationButton {
-
- private final ImageView mButton;
- private AnimatedVectorDrawable mImageDrawable;
-
- RotationButtonImpl(ImageView button) {
- mButton = button;
- }
-
- @Override
- public void setRotationButtonController(RotationButtonController rotationButtonController) {
- // TODO(b/187754252) UI polish, different icons based on light/dark context, etc
- mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
- .getDrawable(rotationButtonController.getIconResId());
- mButton.setImageDrawable(mImageDrawable);
- mButton.setContentDescription(mButton.getResources()
- .getString(R.string.accessibility_rotate_button));
- mImageDrawable.setCallback(mButton);
- }
-
- @Override
- public View getCurrentView() {
- return mButton;
- }
-
- @Override
- public boolean show() {
- mButton.setVisibility(View.VISIBLE);
- mState |= FLAG_ROTATION_BUTTON_VISIBLE;
- applyState();
- return true;
- }
-
- @Override
- public boolean hide() {
- mButton.setVisibility(View.GONE);
- mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
- applyState();
- return true;
- }
-
- @Override
- public boolean isVisible() {
- return mButton.getVisibility() == View.VISIBLE;
- }
-
- @Override
- public void updateIcon(int lightIconColor, int darkIconColor) {
- // TODO(b/187754252): UI Polish
- }
-
- @Override
- public void setOnClickListener(OnClickListener onClickListener) {
- mButton.setOnClickListener(onClickListener);
- }
-
- @Override
- public void setOnHoverListener(OnHoverListener onHoverListener) {
- mButton.setOnHoverListener(onHoverListener);
- }
-
- @Override
- public AnimatedVectorDrawable getImageDrawable() {
- return mImageDrawable;
- }
-
- @Override
- public void setDarkIntensity(float darkIntensity) {
- // TODO(b/187754252) UI polish
- }
-
- @Override
- public boolean acceptRotationProposal() {
- return mButton.isAttachedToWindow();
- }
- }
-
private static class StatePropertyHolder {
private final float mEnabledValue, mDisabledValue;
@@ -1284,13 +1210,16 @@
mAnimator = ObjectAnimator.ofFloat(target, property, enabledValue, disabledValue);
}
- public void setState(int flags) {
+ public void setState(int flags, boolean skipAnimation) {
boolean isEnabled = mEnableCondition.test(flags);
if (mIsEnabled != isEnabled) {
mIsEnabled = isEnabled;
mAnimator.cancel();
mAnimator.setFloatValues(mIsEnabled ? mEnabledValue : mDisabledValue);
mAnimator.start();
+ if (skipAnimation) {
+ mAnimator.end();
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
index 94e2244..caf3320 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
@@ -47,6 +47,7 @@
private final int[] mTmpArr = new int[2];
private @Nullable ObjectAnimator mColorChangeAnim;
+ private Boolean mIsRegionDark;
public StashedHandleView(Context context) {
this(context, null);
@@ -95,7 +96,11 @@
* @param animate Whether to animate the change, or apply it immediately.
*/
public void updateHandleColor(boolean isRegionDark, boolean animate) {
+ if (mIsRegionDark != null && mIsRegionDark == isRegionDark) {
+ return;
+ }
int newColor = isRegionDark ? mStashedHandleLightColor : mStashedHandleDarkColor;
+ mIsRegionDark = isRegionDark;
if (mColorChangeAnim != null) {
mColorChangeAnim.cancel();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 266d0b9..fabf3a5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -41,8 +41,8 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.NavHandle;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import java.io.PrintWriter;
@@ -94,6 +94,7 @@
// States that affect whether region sampling is enabled or not
private boolean mIsStashed;
private boolean mIsLumaSamplingEnabled;
+ private boolean mIsAppTransitionPending;
private boolean mTaskbarHidden;
private float mTranslationYForSwipe;
@@ -212,7 +213,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)) {
@@ -267,6 +268,11 @@
updateSamplingState();
}
+ public void setIsAppTransitionPending(boolean pending) {
+ mIsAppTransitionPending = pending;
+ updateSamplingState();
+ }
+
private void updateSamplingState() {
updateRegionSamplingWindowVisibility();
if (shouldSample()) {
@@ -278,7 +284,7 @@
}
private boolean shouldSample() {
- return mIsStashed && mIsLumaSamplingEnabled;
+ return mIsStashed && mIsLumaSamplingEnabled && !mIsAppTransitionPending;
}
protected void updateStashedHandleHintScale() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9d394a8..0efa949 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -25,10 +25,10 @@
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;
-import static com.android.launcher3.Flags.enableTaskbarCustomization;
import static com.android.launcher3.Utilities.calculateTextHeight;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
@@ -100,6 +100,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
@@ -140,7 +141,6 @@
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewCache;
import com.android.launcher3.views.ActivityContext;
-import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.NavHandle;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
@@ -185,6 +185,7 @@
private final WindowManager mWindowManager;
private DeviceProfile mDeviceProfile;
private WindowManager.LayoutParams mWindowLayoutParams;
+ private WindowManager.LayoutParams mLastUpdatedLayoutParams;
private boolean mIsFullscreen;
// The size we should return to when we call setTaskbarWindowFullscreen(false)
private int mLastRequestedNonFullscreenSize;
@@ -222,21 +223,19 @@
public TaskbarActivityContext(Context windowContext,
@Nullable Context navigationBarPanelContext, DeviceProfile launcherDp,
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
- unfoldTransitionProgressProvider) {
+ unfoldTransitionProgressProvider,
+ @NonNull DesktopVisibilityController desktopVisibilityController) {
super(windowContext);
mNavigationBarPanelContext = navigationBarPanelContext;
applyDeviceProfile(launcherDp);
final Resources resources = getResources();
-
- if (enableTaskbarCustomization()) {
- mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
- mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
- this,
- mTaskbarFeatureEvaluator,
- mDeviceProfile.inv.numRows,
- mDeviceProfile.inv.numColumns);
- }
+ mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
+ mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
+ this,
+ mTaskbarFeatureEvaluator,
+ mDeviceProfile.inv.numRows,
+ mDeviceProfile.inv.numColumns);
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
@@ -285,7 +284,7 @@
TaskbarHotseatDimensionsProvider dimensionsProvider =
new DeviceProfileDimensionsProviderAdapter(this);
BubbleStashController bubbleStashController = isTransientTaskbar
- ? new TransientBubbleStashController(dimensionsProvider, getResources())
+ ? new TransientBubbleStashController(dimensionsProvider, this)
: new PersistentBubbleStashController(dimensionsProvider);
bubbleControllersOptional = Optional.of(new BubbleControllers(
new BubbleBarController(this, bubbleBarView),
@@ -338,15 +337,12 @@
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
- new TaskbarRecentAppsController(
- this,
- RecentsModel.INSTANCE.get(this),
- LauncherActivityInterface.INSTANCE::getDesktopVisibilityController),
+ new TaskbarRecentAppsController(this, RecentsModel.INSTANCE.get(this)),
TaskbarEduTooltipController.newInstance(this),
new KeyboardQuickSwitchController(),
- new TaskbarPinningController(this, () ->
- DisplayController.isInDesktopMode(this)),
- bubbleControllersOptional);
+ new TaskbarPinningController(this),
+ bubbleControllersOptional,
+ new TaskbarDesktopModeController(desktopVisibilityController));
mLauncherPrefs = LauncherPrefs.get(this);
}
@@ -441,6 +437,7 @@
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, getResources(), false);
mLastRequestedNonFullscreenSize = getDefaultTaskbarWindowSize();
mWindowLayoutParams = createAllWindowParams();
+ mLastUpdatedLayoutParams = new WindowManager.LayoutParams();
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
@@ -501,6 +498,15 @@
}
/**
+ * Returns {@code true} iff bubble bar is enabled (but not necessarily visible /
+ * containing bubbles).
+ */
+ @Override
+ public boolean isBubbleBarEnabled() {
+ return getBubbleControllers() != null && BubbleBarController.isBubbleBarEnabled();
+ }
+
+ /**
* Returns if software keyboard is docked or input toolbar is placed at the taskbar area
*/
public boolean isImeDocked() {
@@ -905,11 +911,16 @@
mControllers.navbarButtonsViewController.transitionTo(barMode, animate);
}
+ public void appTransitionPending(boolean pending) {
+ mControllers.stashedHandleViewController.setIsAppTransitionPending(pending);
+ }
+
/**
* Called when this instance of taskbar is no longer needed
*/
public void onDestroy() {
mIsDestroyed = true;
+ mTaskbarFeatureEvaluator.onDestroy();
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
if (!enableTaskbarNoRecreate() && !ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
@@ -927,7 +938,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());
@@ -1194,14 +1205,21 @@
mControllers.uiController.startSplitSelection(splitSelectSource);
}
+ boolean areDesktopTasksVisible() {
+ return mControllers != null
+ && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible();
+ }
+
protected void onTaskbarIconClicked(View view) {
TaskbarUIController taskbarUIController = mControllers.uiController;
RecentsView recents = taskbarUIController.getRecentsView();
boolean shouldCloseAllOpenViews = true;
Object tag = view.getTag();
if (tag instanceof GroupTask groupTask) {
- handleGroupTaskLaunch(groupTask, /* remoteTransition = */ null,
- DisplayController.isInDesktopMode(this));
+ handleGroupTaskLaunch(
+ groupTask,
+ /* remoteTransition= */ null,
+ areDesktopTasksVisible());
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} else if (tag instanceof FolderInfo) {
// Tapping an expandable folder icon on Taskbar
@@ -1422,7 +1440,7 @@
&& !(foundTaskView instanceof DesktopTaskView)) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
- foundTaskView.launchTasks();
+ foundTaskView.launchWithAnimation();
return;
}
}
@@ -1514,6 +1532,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);
+ }
});
}
@@ -1711,6 +1735,12 @@
void notifyUpdateLayoutParams() {
if (mDragLayer.isAttachedToWindow()) {
+ // Copy the current windowLayoutParams to mLastUpdatedLayoutParams and compare the diff.
+ // If there is no change, we will skip the call to updateViewLayout.
+ int changes = mLastUpdatedLayoutParams.copyFrom(mWindowLayoutParams);
+ if (changes == 0) {
+ return;
+ }
if (enableTaskbarNoRecreate()) {
mWindowManager.updateViewLayout(mDragLayer.getRootView(), mWindowLayoutParams);
} else {
@@ -1736,12 +1766,10 @@
return mControllers.taskbarStashController.isInStashedLauncherState();
}
- @Nullable
public TaskbarFeatureEvaluator getTaskbarFeatureEvaluator() {
return mTaskbarFeatureEvaluator;
}
- @Nullable
public TaskbarSpecsEvaluator getTaskbarSpecsEvaluator() {
return mTaskbarSpecsEvaluator;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index ee64060..d6ce3a4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -24,6 +24,7 @@
import android.graphics.Rect
import android.graphics.RectF
import com.android.app.animation.Interpolators
+import com.android.internal.policy.ScreenDecorationsUtils
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.mapRange
@@ -70,8 +71,8 @@
private var keyShadowDistance = 0f
private var bottomMargin = 0
- private val fullCornerRadius = context.cornerRadius.toFloat()
- private var cornerRadius = fullCornerRadius
+ private val fullCornerRadius: Float
+ private var cornerRadius = 0f
private var widthInsetPercentage = 0f
private val square = Path()
private val circle = Path()
@@ -101,7 +102,14 @@
shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
}
- setCornerRoundness(DEFAULT_ROUNDNESS)
+ if (context.areDesktopTasksVisible()) {
+ fullCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
+ cornerRadius = fullCornerRadius
+ } else {
+ fullCornerRadius = context.cornerRadius.toFloat()
+ cornerRadius = fullCornerRadius
+ setCornerRoundness(MAX_ROUNDNESS)
+ }
}
fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) {
@@ -192,7 +200,7 @@
mapRange(
scale,
0f,
- res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin).toFloat()
+ res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin).toFloat(),
)
.toInt()
shadowBlur =
@@ -237,7 +245,7 @@
-mapRange(
1f - progress,
0f,
- if (isAnimatingPinning) 0f else stashedHandleHeight / 2f
+ if (isAnimatingPinning) 0f else stashedHandleHeight / 2f,
)
// Draw shadow.
@@ -247,7 +255,7 @@
shadowBlur,
0f,
keyShadowDistance,
- setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
+ setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha)),
)
strokePaint.alpha = (paint.alpha * strokeAlpha) / 255
@@ -255,7 +263,7 @@
transientBackgroundBounds.left + halfWidthDelta + hotseatOffsetLeft,
bottom - newBackgroundHeight + hotseatOffsetTop,
transientBackgroundBounds.right - halfWidthDelta + hotseatOffsetRight,
- bottom + hotseatOffsetBottom
+ bottom + hotseatOffsetBottom,
)
val horizontalInset = fullWidth * widthInsetPercentage
lastDrawnTransientRect.inset(horizontalInset, 0f)
@@ -273,7 +281,7 @@
}
companion object {
- const val DEFAULT_ROUNDNESS = 1f
+ const val MAX_ROUNDNESS = 1f
private const val DARK_THEME_STROKE_ALPHA = 51
private const val LIGHT_THEME_STROKE_ALPHA = 41
private const val DARK_THEME_SHADOW_ALPHA = 51f
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index d94d9175..56fd2bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -64,6 +64,7 @@
public final KeyboardQuickSwitchController keyboardQuickSwitchController;
public final TaskbarPinningController taskbarPinningController;
public final Optional<BubbleControllers> bubbleControllers;
+ public final TaskbarDesktopModeController taskbarDesktopModeController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null;
@@ -111,7 +112,8 @@
TaskbarEduTooltipController taskbarEduTooltipController,
KeyboardQuickSwitchController keyboardQuickSwitchController,
TaskbarPinningController taskbarPinningController,
- Optional<BubbleControllers> bubbleControllers) {
+ Optional<BubbleControllers> bubbleControllers,
+ TaskbarDesktopModeController taskbarDesktopModeController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -138,6 +140,7 @@
this.keyboardQuickSwitchController = keyboardQuickSwitchController;
this.taskbarPinningController = taskbarPinningController;
this.bubbleControllers = bubbleControllers;
+ this.taskbarDesktopModeController = taskbarDesktopModeController;
}
/**
@@ -173,6 +176,7 @@
taskbarEduTooltipController.init(this);
keyboardQuickSwitchController.init(this);
taskbarPinningController.init(this, mSharedState);
+ taskbarDesktopModeController.init(this, mSharedState);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -188,8 +192,18 @@
taskbarDragLayerController, taskbarScrimViewController,
voiceInteractionWindowController
};
- mCornerRoundness.updateValue(TaskbarBackgroundRenderer.DEFAULT_ROUNDNESS);
+ if (taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ mCornerRoundness.updateValue(taskbarDesktopModeController.getTaskbarCornerRoundness(
+ mSharedState.showCornerRadiusInDesktopMode));
+ } else {
+ mCornerRoundness.updateValue(TaskbarBackgroundRenderer.MAX_ROUNDNESS);
+ }
+ onPostInit();
+ }
+
+ @VisibleForTesting
+ public void onPostInit() {
mAreAllControllersInitialized = true;
for (Runnable postInitCallback : mPostInitCallbacks) {
postInitCallback.run();
@@ -248,6 +262,7 @@
keyboardQuickSwitchController.onDestroy();
taskbarStashController.onDestroy();
bubbleControllers.ifPresent(controllers -> controllers.onDestroy());
+ taskbarDesktopModeController.onDestroy();
mControllersToLog = null;
mBackgroundRendererControllers = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
new file mode 100644
index 0000000..47a35c5
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.launcher3.statehandlers.DesktopVisibilityController.TaskbarDesktopModeListener
+import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
+
+/** Handles Taskbar in Desktop Windowing mode. */
+class TaskbarDesktopModeController(
+ private val desktopVisibilityController: DesktopVisibilityController
+) : TaskbarDesktopModeListener {
+ private lateinit var taskbarControllers: TaskbarControllers
+ private lateinit var taskbarSharedState: TaskbarSharedState
+
+ val areDesktopTasksVisible: Boolean
+ get() = desktopVisibilityController.areDesktopTasksVisible()
+
+ fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) {
+ taskbarControllers = controllers
+ taskbarSharedState = sharedState
+ desktopVisibilityController.registerTaskbarDesktopModeListener(this)
+ }
+
+ override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {
+ taskbarSharedState.showCornerRadiusInDesktopMode = doesAnyTaskRequireTaskbarRounding
+ val cornerRadius = getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding)
+ taskbarControllers.taskbarCornerRoundness.animateToValue(cornerRadius).start()
+ }
+
+ fun getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding: Boolean): Float {
+ return if (doesAnyTaskRequireTaskbarRounding) {
+ MAX_ROUNDNESS
+ } else {
+ 0f
+ }
+ }
+
+ fun onDestroy() = desktopVisibilityController.unregisterTaskbarDesktopModeListener(this)
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index a635537..b5a3314 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -169,8 +169,11 @@
override fun addArrow() {
super.addArrow()
+ val location = IntArray(2)
+ popupContainer.getLocationInDragLayer(dividerView, location)
+ val dividerViewX = location[0].toFloat()
// Change arrow location to the middle of popup.
- mArrow.x = (dividerView.x + dividerView.width / 2) - (mArrowWidth / 2)
+ mArrow.x = (dividerViewX + dividerView.width / 2) - (mArrowWidth / 2)
}
override fun updateArrowColor() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index efe42fb..fc307b2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -74,19 +74,17 @@
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.views.BubbleTextHolder;
-import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LogUtils;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.draganddrop.DragAndDropConstants;
+import com.android.wm.shell.shared.draganddrop.DragAndDropConstants;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -344,12 +342,9 @@
protected void callOnDragStart() {
super.callOnDragStart();
// TODO(297921594) clean it up when taskbar to desktop drag is implemented.
- DesktopVisibilityController desktopController =
- LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
-
// Pre-drag has ended, start the global system drag.
- if (mDisallowGlobalDrag || (desktopController != null
- && desktopController.areDesktopTasksVisible())) {
+ if (mDisallowGlobalDrag
+ || mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS);
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index ff890fb..2845cee 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -171,6 +171,10 @@
}
private void updateBackgroundAlpha() {
+ if (mActivity.isPhoneMode()) {
+ return;
+ }
+
final float bgNavbar = mBgNavbar.value;
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
* mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
@@ -291,7 +295,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..3bff31f 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,19 +41,16 @@
* 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;
private final View mHoverView;
private final ArrowTipView mHoverToolTipView;
private final String mToolTipText;
+ private final int mYOffset;
public TaskbarHoverToolTipController(TaskbarActivityContext activity, TaskbarView taskbarView,
View hoverView) {
@@ -90,69 +79,36 @@
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);
+ mYOffset = arrowContextWrapper.getResources().getDimensionPixelSize(
+ R.dimen.taskbar_tooltip_y_offset);
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);
mHoverToolTipView.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
mHoverToolTipView.setPivotY(bottom);
- mHoverToolTipView.setY(mTaskbarView.getTop() - (bottom - top));
+ mHoverToolTipView.setY(mTaskbarView.getTop() - mYOffset - (bottom - top));
});
}
@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() {
@@ -168,16 +124,6 @@
}
Rect iconViewBounds = Utilities.getViewBounds(mHoverView);
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);
+ mTaskbarView.getTop() - mYOffset, /* shouldAutoClose= */ false);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 9dee473..221504d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -56,7 +56,6 @@
import com.android.launcher3.util.Executors
import java.io.PrintWriter
import kotlin.jvm.optionals.getOrNull
-import kotlin.math.max
/** Handles the insets that Taskbar provides to underlying apps and the IME. */
class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -106,7 +105,8 @@
}
fun onTaskbarOrBubblebarWindowHeightOrInsetsChanged() {
- val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
+ val taskbarStashController = controllers.taskbarStashController
+ val tappableHeight = taskbarStashController.tappableHeightToReportToApps
// We only report tappableElement height for unstashed, persistent taskbar,
// which is also when we draw the rounded corners above taskbar.
val insetsRoundedCornerFlag =
@@ -133,17 +133,11 @@
}
val bubbleControllers = controllers.bubbleControllers.getOrNull()
- val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
+ val taskbarTouchableHeight = taskbarStashController.touchableHeight
val bubblesTouchableHeight =
bubbleControllers?.bubbleStashController?.getTouchableHeight() ?: 0
- // add bounds for task bar and bubble bar stash controllers
- val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
- defaultTouchableRegion.set(
- 0,
- windowLayoutParams.height - touchableHeight,
- context.deviceProfile.widthPx,
- windowLayoutParams.height
- )
+ // reset touch bounds
+ defaultTouchableRegion.setEmpty()
if (bubbleControllers != null) {
val bubbleBarViewController = bubbleControllers.bubbleBarViewController
val isBubbleBarVisible = bubbleControllers.bubbleStashController.isBubbleBarVisible()
@@ -153,6 +147,13 @@
defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds)
}
}
+ if (taskbarStashController.isInApp || taskbarStashController.isInOverview) {
+ // only add the taskbar touch region if not on home
+ val bottom = windowLayoutParams.height
+ val top = bottom - taskbarTouchableHeight
+ val right = context.deviceProfile.widthPx
+ defaultTouchableRegion.addBoundsToRegion(Rect(/* left= */ 0, top, right, bottom))
+ }
// Pre-calculate insets for different providers across different rotations for this gravity
for (rotation in Surface.ROTATION_0..Surface.ROTATION_270) {
@@ -221,20 +222,20 @@
provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity, endRotation)
} else if (provider.type == mandatorySystemGestures()) {
if (context.isThreeButtonNav) {
- provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity,
- endRotation)
+ provider.insetsSize =
+ getInsetsForGravityWithCutout(contentHeight, gravity, endRotation)
} else {
val gestureHeight =
- ResourceUtils.getNavbarSize(
+ ResourceUtils.getNavbarSize(
ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
- context.resources)
- val isPinnedTaskbar = context.deviceProfile.isTaskbarPresent
- && !context.deviceProfile.isTransientTaskbar
- val mandatoryGestureHeight =
- if (isPinnedTaskbar) contentHeight
- else gestureHeight
- provider.insetsSize = getInsetsForGravityWithCutout(mandatoryGestureHeight, gravity,
- endRotation)
+ context.resources
+ )
+ val isPinnedTaskbar =
+ context.deviceProfile.isTaskbarPresent &&
+ !context.deviceProfile.isTransientTaskbar
+ val mandatoryGestureHeight = if (isPinnedTaskbar) contentHeight else gestureHeight
+ provider.insetsSize =
+ getInsetsForGravityWithCutout(mandatoryGestureHeight, gravity, endRotation)
}
} else if (provider.type == tappableElement()) {
provider.insetsSize = getInsetsForGravity(tappableHeight, gravity)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index e6b3acd..6c6bd71 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_AWAKE;
@@ -146,6 +147,7 @@
private MultiProperty mIconAlphaForHome;
private QuickstepLauncher mLauncher;
+ private boolean mIsDestroyed = false;
private Integer mPrevState;
private int mState;
private LauncherState mLauncherState = LauncherState.NORMAL;
@@ -244,7 +246,9 @@
resetIconAlignment();
- mLauncher.getStateManager().addStateListener(mStateListener);
+ if (!mControllers.taskbarActivityContext.isPhoneMode()) {
+ mLauncher.getStateManager().addStateListener(mStateListener);
+ }
mLauncherState = launcher.getStateManager().getState();
updateStateForSysuiFlags(sysuiStateFlags, /*applyState*/ false);
@@ -256,6 +260,7 @@
}
public void onDestroy() {
+ mIsDestroyed = true;
mCanSyncViews = false;
mIconAlignment.finishAnimation();
@@ -349,8 +354,10 @@
// interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in
// when the device is asleep, the second condition extends ensures that the transition from
// and to the WAKEFULNESS_ASLEEP state also hide the taskbar, and improves the taskbar
- // hide/reveal animation timings.
- boolean isTaskbarHidden = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_DEVICE_DREAMING)
+ // hide/reveal animation timings. The Taskbar can show when dreaming if the glanceable hub
+ // is showing on top.
+ boolean isTaskbarHidden = (hasAnyFlag(systemUiStateFlags, SYSUI_STATE_DEVICE_DREAMING)
+ && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_COMMUNAL_HUB_SHOWING))
|| (systemUiStateFlags & SYSUI_STATE_WAKEFULNESS_MASK) != WAKEFULNESS_AWAKE;
updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden);
@@ -367,7 +374,7 @@
private void updateOverviewDragState(LauncherState launcherState) {
boolean disallowLongClick =
FeatureFlags.enableSplitContextually()
- ? mLauncher.isSplitSelectionActive()
+ ? mLauncher.isSplitSelectionActive() || mIsAnimatingToLauncher
: launcherState == LauncherState.OVERVIEW_SPLIT_SELECT;
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
mControllers, launcherState.disallowTaskbarGlobalDrag(),
@@ -407,7 +414,7 @@
}
public Animator applyState(long duration, boolean start) {
- if (mControllers.taskbarActivityContext.isDestroyed()) {
+ if (mIsDestroyed || mControllers.taskbarActivityContext.isPhoneMode()) {
return null;
}
Animator animator = null;
@@ -433,6 +440,11 @@
return animator;
}
+ /** Returns {@code true} if launcher is currently presenting the home screen. */
+ public boolean isOnHome() {
+ return isInLauncher() && mLauncherState == LauncherState.NORMAL;
+ }
+
private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
final boolean isInLauncher = isInLauncher();
final boolean isIconAlignedWithHotseat = isIconAlignedWithHotseat();
@@ -445,13 +457,13 @@
}
mControllers.bubbleControllers.ifPresent(controllers -> {
// Show the bubble bar when on launcher home or in overview.
- boolean onHome = isInLauncher && mLauncherState == LauncherState.NORMAL;
boolean onOverview = mLauncherState == LauncherState.OVERVIEW;
- controllers.bubbleStashController.setBubblesShowingOnHome(onHome);
+ controllers.bubbleStashController.setBubblesShowingOnHome(isOnHome());
controllers.bubbleStashController.setBubblesShowingOnOverview(onOverview);
});
- mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_OVERVIEW,
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_IN_OVERVIEW,
mLauncherState == LauncherState.OVERVIEW);
AnimatorSet animatorSet = new AnimatorSet();
@@ -483,8 +495,6 @@
public void onAnimationStart(Animator animation) {
mIsAnimatingToLauncher = isInLauncher;
- TaskbarStashController stashController =
- mControllers.taskbarStashController;
if (DEBUG) {
Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !isInLauncher);
}
@@ -500,6 +510,8 @@
// Handle closing open popups when going home/overview
handleOpenFloatingViews = true;
+ } else {
+ stashController.applyState();
}
if (handleOpenFloatingViews && isInLauncher) {
@@ -580,6 +592,13 @@
float cornerRoundness = isInLauncher ? 0 : 1;
+ if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()
+ && mControllers.getSharedState() != null) {
+ cornerRoundness =
+ mControllers.taskbarDesktopModeController.getTaskbarCornerRoundness(
+ mControllers.getSharedState().showCornerRadiusInDesktopMode);
+ }
+
// Don't animate if corner roundness has reached desired value.
if (mTaskbarCornerRoundness.isAnimating()
|| mTaskbarCornerRoundness.value != cornerRoundness) {
@@ -749,7 +768,7 @@
}
private void updateIconAlphaForHome(float alpha) {
- if (mControllers.taskbarActivityContext.isDestroyed()) {
+ if (mIsDestroyed) {
return;
}
mIconAlphaForHome.setValue(alpha);
@@ -852,7 +871,8 @@
"%s\tmTaskbarBackgroundAlpha=%.2f", prefix, mTaskbarBackgroundAlpha.value));
pw.println(String.format(
"%s\tmIconAlphaForHome=%.2f", prefix, mIconAlphaForHome.getValue()));
- pw.println(String.format("%s\tmPrevState=%s", prefix, getStateString(mPrevState)));
+ pw.println(String.format("%s\tmPrevState=%s", prefix,
+ mPrevState == null ? null : getStateString(mPrevState)));
pw.println(String.format("%s\tmState=%s", prefix, getStateString(mState)));
pw.println(String.format("%s\tmLauncherState=%s", prefix, mLauncherState));
pw.println(String.format(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index f411e79..1b4db7a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -60,6 +60,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
@@ -209,12 +210,14 @@
}
};
+ @NonNull private final DesktopVisibilityController mDesktopVisibilityController;
+
@SuppressLint("WrongConstant")
public TaskbarManager(
Context context,
AllAppsActionManager allAppsActionManager,
- TaskbarNavButtonCallbacks navCallbacks) {
-
+ TaskbarNavButtonCallbacks navCallbacks,
+ @NonNull DesktopVisibilityController desktopVisibilityController) {
Display display =
context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = context.createWindowContext(display,
@@ -224,6 +227,7 @@
mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
? context.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
: null;
+ mDesktopVisibilityController = desktopVisibilityController;
if (enableTaskbarNoRecreate()) {
mWindowManager = mContext.getSystemService(WindowManager.class);
mTaskbarRootLayout = new FrameLayout(mContext) {
@@ -459,16 +463,18 @@
+ " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
+ " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
+ " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent));
- if (!isTaskbarEnabled) {
+ if (!isTaskbarEnabled || !isLargeScreenTaskbar) {
SystemUiProxy.INSTANCE.get(mContext)
.notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
- return;
+ if (!isTaskbarEnabled) {
+ return;
+ }
}
if (enableTaskbarNoRecreate() || mTaskbarActivityContext == null) {
mTaskbarActivityContext = new TaskbarActivityContext(mContext,
mNavigationBarPanelContext, dp, mNavButtonController,
- mUnfoldProgressProvider);
+ mUnfoldProgressProvider, mDesktopVisibilityController);
} else {
mTaskbarActivityContext.updateDeviceProfile(dp);
}
@@ -547,7 +553,15 @@
public void transitionTo(@BarTransitions.TransitionMode int barMode,
boolean animate) {
- mTaskbarActivityContext.transitionTo(barMode, animate);
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.transitionTo(barMode, animate);
+ }
+ }
+
+ public void appTransitionPending(boolean pending) {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.appTransitionPending(pending);
+ }
}
private boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index 6c9cc64..1867cd0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -32,10 +32,8 @@
import java.io.PrintWriter
/** Controls taskbar pinning through a popup view. */
-class TaskbarPinningController(
- private val context: TaskbarActivityContext,
- private val isInDesktopModeProvider: () -> Boolean,
-) : TaskbarControllers.LoggableTaskbarController {
+class TaskbarPinningController(private val context: TaskbarActivityContext) :
+ TaskbarControllers.LoggableTaskbarController {
private lateinit var controllers: TaskbarControllers
private lateinit var taskbarSharedState: TaskbarSharedState
@@ -58,7 +56,7 @@
return
}
val shouldPinTaskbar =
- if (isInDesktopModeProvider()) {
+ if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) {
!launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
} else {
!launcherPrefs.get(TASKBAR_PINNING)
@@ -119,7 +117,7 @@
dragLayerController.taskbarBackgroundProgress.animateToValue(animateToValue),
taskbarViewController.taskbarIconTranslationYForPinning.animateToValue(animateToValue),
taskbarViewController.taskbarIconScaleForPinning.animateToValue(animateToValue),
- taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
+ taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue),
)
animatorSet.interpolator = Interpolators.EMPHASIZED
@@ -134,10 +132,10 @@
@VisibleForTesting
fun recreateTaskbarAndUpdatePinningValue() {
updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
- if (isInDesktopModeProvider()) {
+ if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) {
launcherPrefs.put(
TASKBAR_PINNING_IN_DESKTOP_MODE,
- !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
+ !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE),
)
} else {
launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index b697590..2cee77d 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.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ 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 1a168a9..72bdafe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -21,7 +21,6 @@
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.TaskItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
-import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.launcher3.util.CancellableTask
import com.android.quickstep.RecentsModel
@@ -36,13 +35,8 @@
* - When in Fullscreen mode: show the N most recent Tasks
* - When in Desktop Mode: show the currently running (open) Tasks
*/
-class TaskbarRecentAppsController(
- context: Context,
- private val recentsModel: RecentsModel,
- // Pass a provider here instead of the actual DesktopVisibilityController instance since that
- // instance might not be available when this constructor is called.
- private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?,
-) : LoggableTaskbarController {
+class TaskbarRecentAppsController(context: Context, private val recentsModel: RecentsModel) :
+ LoggableTaskbarController {
var canShowRunningApps =
DesktopModeStatus.canEnterDesktopMode(context) &&
@@ -78,19 +72,16 @@
var shownTasks: List<GroupTask> = emptyList()
private set
- private val desktopVisibilityController: DesktopVisibilityController?
- get() = desktopVisibilityControllerProvider()
-
- private val isInDesktopMode: Boolean
- get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
-
val runningTaskIds: Set<Int>
/**
* Returns the task IDs of apps that should be indicated as "running" to the user.
* Specifically, we return all the open tasks if we are in Desktop mode, else emptySet().
*/
get() {
- if (!canShowRunningApps || !isInDesktopMode) {
+ if (
+ !canShowRunningApps ||
+ !controllers.taskbarDesktopModeController.areDesktopTasksVisible
+ ) {
return emptySet()
}
val tasks = desktopTask?.tasks ?: return emptySet()
@@ -102,7 +93,10 @@
* Returns the task IDs for the tasks that should be indicated as "minimized" to the user.
*/
get() {
- if (!canShowRunningApps || !isInDesktopMode) {
+ if (
+ !canShowRunningApps ||
+ !controllers.taskbarDesktopModeController.areDesktopTasksVisible
+ ) {
return emptySet()
}
val desktopTasks = desktopTask?.tasks ?: return emptySet()
@@ -124,7 +118,7 @@
controllers = taskbarControllers
if (canShowRunningApps || canShowRecentApps) {
recentsModel.registerRecentTasksChangedListener(recentTasksChangedListener)
- reloadRecentTasksIfNeeded()
+ controllers.runAfterInit { reloadRecentTasksIfNeeded() }
}
}
@@ -137,8 +131,10 @@
/** Called to update hotseatItems, in order to de-dupe them from Recent/Running tasks later. */
fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
// Ignore predicted apps - we show running or recent apps instead.
+ val areDesktopTasksVisible = controllers.taskbarDesktopModeController.areDesktopTasksVisible
val removePredictions =
- (isInDesktopMode && canShowRunningApps) || (!isInDesktopMode && canShowRecentApps)
+ (areDesktopTasksVisible && canShowRunningApps) ||
+ (!areDesktopTasksVisible && canShowRecentApps)
if (!removePredictions) {
shownHotseatItems = hotseatItems.filterNotNull()
onRecentsOrHotseatChanged()
@@ -150,11 +146,11 @@
.filter { itemInfo -> !itemInfo.isPredictedItem }
.toMutableList()
- if (isInDesktopMode && canShowRunningApps) {
+ if (areDesktopTasksVisible && canShowRunningApps) {
shownHotseatItems =
updateHotseatItemsFromRunningTasks(
getOrderedAndWrappedDesktopTasks(),
- shownHotseatItems
+ shownHotseatItems,
)
}
@@ -199,7 +195,7 @@
val oldShownTasks = shownTasks
orderedRunningTaskIds = updateOrderedRunningTaskIds()
shownTasks =
- if (isInDesktopMode) {
+ if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) {
computeShownRunningTasks()
} else {
computeShownRecentTasks()
@@ -281,7 +277,7 @@
private fun dedupeHotseatTasks(
groupTasks: List<GroupTask>,
- shownHotseatItems: List<ItemInfo>
+ shownHotseatItems: List<ItemInfo>,
): List<GroupTask> {
val hotseatPackages = shownHotseatItems.map { item -> item.targetPackage }
return groupTasks.filter { groupTask ->
@@ -296,7 +292,7 @@
*/
private fun updateHotseatItemsFromRunningTasks(
groupTasks: List<GroupTask>,
- shownHotseatItems: List<ItemInfo>
+ shownHotseatItems: List<ItemInfo>,
): List<ItemInfo> =
shownHotseatItems.map { itemInfo ->
if (itemInfo is TaskItemInfo) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 5e7c7ce..2370dfd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -21,13 +21,14 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
-import static com.android.wm.shell.common.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
+import static com.android.wm.shell.shared.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
import android.animation.ObjectAnimator;
import android.view.animation.Interpolator;
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/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 77bd35f..729cbe9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -102,5 +102,8 @@
// To track if taskbar was stashed / unstashed between configuration changes (which recreates
// the task bar).
- public Boolean taskbarWasStashedAuto = true;
+ public boolean taskbarWasStashedAuto = true;
+
+ // should show corner radius on persistent taskbar when in desktop mode.
+ public boolean showCornerRadiusInDesktopMode = false;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 5d6fdc1..c1ed39a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -63,10 +63,8 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
-import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.SystemUiFlagUtils;
@@ -96,7 +94,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;
@@ -153,12 +150,12 @@
/**
* How long to delay the icon/stash handle alpha.
*/
- private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
+ public static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
/**
* How long the icon/stash handle alpha animation plays.
*/
- private static final long TASKBAR_STASH_ALPHA_DURATION = 50;
+ public static final long TASKBAR_STASH_ALPHA_DURATION = 50;
/**
* How long to delay the icon/stash handle alpha for the home to app taskbar animation.
@@ -425,6 +422,11 @@
return hasAnyFlag(FLAGS_IN_APP);
}
+ /** Returns whether the taskbar is currently in overview screen. */
+ public boolean isInOverview() {
+ return hasAnyFlag(FLAG_IN_OVERVIEW);
+ }
+
/**
* Returns the height that taskbar will be touchable.
*/
@@ -572,6 +574,7 @@
/* isStashed= */ mActivity.isPhoneMode(),
placeholderDuration,
TRANSITION_UNSTASH_SUW_MANUAL,
+ /* skipTaskbarBackgroundDelay */ false,
/* jankTag= */ "SUW_MANUAL");
animation.addListener(AnimatorListeners.forEndCallback(
() -> mControllers.taskbarViewController.setDeferUpdatesForSUW(false)));
@@ -581,13 +584,14 @@
/**
* Create a stash animation and save to {@link #mAnimator}.
*
- * @param isStashed whether it's a stash animation or an unstash animation
- * @param duration duration of the animation
- * @param animationType what transition type to play.
- * @param jankTag tag to be used in jank monitor trace.
+ * @param isStashed whether it's a stash animation or an unstash animation
+ * @param duration duration of the animation
+ * @param animationType what transition type to play.
+ * @param skipTaskbarBackgroundDelay Iff true, skips delaying the taskbar background.
+ * @param jankTag tag to be used in jank monitor trace.
*/
private void createAnimToIsStashed(boolean isStashed, long duration,
- @StashAnimation int animationType, String jankTag) {
+ @StashAnimation int animationType, boolean skipTaskbarBackgroundDelay, String jankTag) {
if (animationType == TRANSITION_UNSTASH_SUW_MANUAL && isStashed) {
// The STASH_ANIMATION_SUW_MANUAL must only be used during an unstash animation.
Log.e(TAG, "Illegal arguments:Using TRANSITION_UNSTASH_SUW_MANUAL to stash taskbar");
@@ -625,7 +629,8 @@
}
if (isTransientTaskbar) {
- createTransientAnimToIsStashed(mAnimator, isStashed, duration, animationType);
+ createTransientAnimToIsStashed(mAnimator, isStashed, duration,
+ skipTaskbarBackgroundDelay, animationType);
} else {
createAnimToIsStashed(mAnimator, isStashed, duration, stashTranslation, animationType);
}
@@ -731,7 +736,7 @@
}
private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- @StashAnimation int animationType) {
+ boolean skipTaskbarBackgroundDelay, @StashAnimation int animationType) {
// Target values of the properties this is going to set
final float backgroundOffsetTarget = isStashed ? 1 : 0;
final float iconAlphaTarget = isStashed ? 0 : 1;
@@ -782,7 +787,7 @@
backgroundAndHandleAlphaStartDelay,
backgroundAndHandleAlphaDuration, LINEAR);
- if (enableScalingRevealHomeAnimation() && !isStashed) {
+ if (enableScalingRevealHomeAnimation() && isStashed && !skipTaskbarBackgroundDelay) {
play(as, getTaskbarBackgroundAnimatorWhenNotGoingHome(duration),
0, 0, LINEAR);
as.addListener(AnimatorListeners.forEndCallback(
@@ -1022,6 +1027,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;
@@ -1071,10 +1080,9 @@
}
// Do not stash if hardware keyboard is attached, in 3 button nav and desktop windowing mode
- DesktopVisibilityController visibilityController =
- LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
- if (visibilityController != null && mActivity.isHardwareKeyboard()
- && mActivity.isThreeButtonNav() && visibilityController.areDesktopTasksVisible()) {
+ if (mActivity.isHardwareKeyboard()
+ && mActivity.isThreeButtonNav()
+ && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
return false;
}
@@ -1129,6 +1137,10 @@
TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
!hasAnyFlag(FLAG_STASHED_IN_APP_AUTO));
}
+ if (hasAnyFlag(changedFlags, FLAG_IN_OVERVIEW | FLAG_IN_APP)) {
+ mControllers.runAfterInit(() -> mControllers.taskbarInsetsController
+ .onTaskbarOrBubblebarWindowHeightOrInsetsChanged());
+ }
mActivity.applyForciblyShownFlagWhileTransientTaskbarUnstashed(!isStashedInApp());
}
@@ -1143,7 +1155,8 @@
*/
public void setUpTaskbarSystemAction(boolean visible) {
UI_HELPER_EXECUTOR.execute(() -> {
- if (!visible || !DisplayController.isTransientTaskbar(mActivity)) {
+ if (!visible || !DisplayController.isTransientTaskbar(mActivity)
+ || mActivity.isPhoneMode()) {
mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_TASKBAR);
mIsTaskbarSystemActionRegistered = false;
return;
@@ -1167,6 +1180,12 @@
* Clean up on destroy from TaskbarControllers
*/
public void onDestroy() {
+ // If the controller is destroyed before the animation finishes, we cancel the animation
+ // so that we don't finish the CUJ.
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ mAnimator = null;
+ }
UI_HELPER_EXECUTOR.execute(
() -> mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_TASKBAR));
}
@@ -1281,11 +1300,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) {
@@ -1335,8 +1349,10 @@
mIsStashed = isStashed;
mLastStartedTransitionType = animationType;
+ boolean skipTaskbarBgDelay = !hasAnyFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS)
+ && hasAnyFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, changedFlags);
// This sets mAnimator.
- createAnimToIsStashed(mIsStashed, duration, animationType,
+ createAnimToIsStashed(mIsStashed, duration, animationType, skipTaskbarBgDelay,
computeTaskbarJankMonitorTag(changedFlags));
return mAnimator;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java
index 5b6fbef..17516f3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java
@@ -25,7 +25,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
/**
* Utility class that contains the different taskbar thresholds logic.
@@ -39,10 +38,6 @@
private static int getThreshold(Resources r, DeviceProfile dp, int thresholdDimen,
int multiplierDimen) {
- if (!FeatureFlags.ENABLE_DYNAMIC_TASKBAR_THRESHOLDS.get()) {
- return r.getDimensionPixelSize(thresholdDimen);
- }
-
float landscapeScreenHeight = dp.isLandscape ? dp.heightPx : dp.widthPx;
float screenPart = (landscapeScreenHeight * SCREEN_UNITS);
float defaultDp = dpiFromPx(screenPart, DisplayMetrics.DENSITY_DEVICE_STABLE);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 2ada5ba..6b1173a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
-import static com.android.quickstep.OverviewCommandHelper.TYPE_HIDE;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
@@ -40,6 +39,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
@@ -61,6 +61,8 @@
// Initialized in init.
protected TaskbarControllers mControllers;
+ protected boolean mSkipLauncherVisibilityChange;
+
@CallSuper
protected void init(TaskbarControllers taskbarControllers) {
mControllers = taskbarControllers;
@@ -96,14 +98,7 @@
}
/** Called when an icon is launched. */
- @CallSuper
- public void onTaskbarIconLaunched(ItemInfo item) {
- // When launching from Taskbar, e.g. from Overview, set FLAG_IN_APP immediately instead of
- // waiting for onPause, to reduce potential visual noise during the app open transition.
- if (mControllers.taskbarStashController == null) return;
- mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, true);
- mControllers.taskbarStashController.applyState();
- }
+ public void onTaskbarIconLaunched(ItemInfo item) { }
public View getRootView() {
return mControllers.taskbarActivityContext.getDragLayer();
@@ -230,7 +225,7 @@
}
recentsView.getSplitSelectController().findLastActiveTasksAndRunCallback(
- Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
+ Collections.singletonList(splitSelectSource.getItemInfo().getComponentKey()),
false /* findExactPairMatch */,
foundTasks -> {
@Nullable Task foundTask = foundTasks[0];
@@ -247,6 +242,13 @@
* Uses the clicked Taskbar icon to launch a second app for splitscreen.
*/
public void triggerSecondAppForSplit(ItemInfoWithIcon info, Intent intent, View startingView) {
+ // When launching from Taskbar, e.g. from Overview, set FLAG_IN_APP immediately
+ // to reduce potential visual noise during the app open transition.
+ if (mControllers.taskbarStashController != null) {
+ mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, true);
+ mControllers.taskbarStashController.applyState();
+ }
+
RecentsView recents = getRecentsView();
recents.getSplitSelectController().findLastActiveTasksAndRunCallback(
Collections.singletonList(info.getComponentKey()),
@@ -392,7 +394,7 @@
if (overviewCommandHelper == null) {
return;
}
- overviewCommandHelper.addCommand(TYPE_HIDE);
+ overviewCommandHelper.addCommand(CommandType.HIDE);
}
/**
@@ -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..32d6561 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -22,10 +22,8 @@
import static com.android.launcher3.Flags.enableRecentsInTaskbar;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
import android.content.res.Resources;
@@ -39,12 +37,9 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
-import androidx.annotation.DimenRes;
-import androidx.annotation.DrawableRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -62,17 +57,16 @@
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.taskbar.customization.TaskbarAllAppsButtonContainer;
+import com.android.launcher3.taskbar.customization.TaskbarDividerContainer;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconButtonView;
-import com.android.quickstep.DeviceConfigWrapper;
-import com.android.quickstep.util.AssistStateManager;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.util.List;
import java.util.function.Predicate;
@@ -100,16 +94,19 @@
private View.OnLongClickListener mIconLongClickListener;
// Only non-null when the corresponding Folder is open.
- private @Nullable FolderIcon mLeaveBehindFolderIcon;
+ @Nullable private FolderIcon mLeaveBehindFolderIcon;
// Only non-null when device supports having an All Apps button.
- private @Nullable IconButtonView mAllAppsButton;
- private Runnable mAllAppsTouchRunnable;
- private long mAllAppsButtonTouchDelayMs;
- private boolean mAllAppsTouchTriggered;
+ @Nullable private final TaskbarAllAppsButtonContainer mAllAppsButtonContainer;
// Only non-null when device supports having an All Apps button.
- private @Nullable IconButtonView mTaskbarDivider;
+ @Nullable private TaskbarDividerContainer mTaskbarDividerContainer;
+
+ /**
+ * Whether the divider is between Hotseat icons and Recents,
+ * instead of between All Apps button and Hotseat.
+ */
+ private boolean mAddedDividerForRecents;
private final View mQsb;
@@ -167,55 +164,14 @@
// Needed to draw folder leave-behind when opening one.
setWillNotDraw(false);
- mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
- .inflate(R.layout.taskbar_all_apps_button, this, false);
- mAllAppsButton.setIconDrawable(resources.getDrawable(
- getAllAppsButton(isTransientTaskbar)));
- mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
- mAllAppsButton.setForegroundTint(
- mActivityContext.getColor(R.color.all_apps_button_color));
+ mAllAppsButtonContainer = new TaskbarAllAppsButtonContainer(context);
if (enableTaskbarPinning() || enableRecentsInTaskbar()) {
- mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
- R.layout.taskbar_divider,
- this, false);
- mTaskbarDivider.setIconDrawable(
- resources.getDrawable(R.drawable.taskbar_divider_button));
- mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ mTaskbarDividerContainer = new TaskbarDividerContainer(context);
}
// TODO: Disable touch events on QSB otherwise it can crash.
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
-
- // Default long press (touch) delay = 400ms
- mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout();
- }
-
- @DrawableRes
- private int getAllAppsButton(boolean isTransientTaskbar) {
- boolean shouldSelectTransientIcon =
- (isTransientTaskbar || enableTaskbarPinning())
- && !mActivityContext.isThreeButtonNav();
- if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
- return shouldSelectTransientIcon
- ? R.drawable.ic_transient_taskbar_all_apps_search_button
- : R.drawable.ic_taskbar_all_apps_search_button;
- } else {
- return shouldSelectTransientIcon
- ? R.drawable.ic_transient_taskbar_all_apps_button
- : R.drawable.ic_taskbar_all_apps_button;
- }
- }
-
- @DimenRes
- public int getAllAppsButtonTranslationXOffset(boolean isTransientTaskbar) {
- if (isTransientTaskbar) {
- return R.dimen.transient_taskbar_all_apps_button_translation_x_offset;
- } else {
- return ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()
- ? R.dimen.taskbar_all_apps_search_button_translation_x_offset
- : R.dimen.taskbar_all_apps_button_translation_x_offset;
- }
}
@Override
@@ -300,27 +256,11 @@
mIconClickListener = mControllerCallbacks.getIconOnClickListener();
mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener();
- if (mAllAppsButton != null) {
- mAllAppsButton.setOnClickListener(this::onAllAppsButtonClick);
- mAllAppsButton.setOnLongClickListener(this::onAllAppsButtonLongClick);
- mAllAppsButton.setOnTouchListener(this::onAllAppsButtonTouch);
- mAllAppsButton.setHapticFeedbackEnabled(
- mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled());
- mAllAppsTouchRunnable = () -> {
- mControllerCallbacks.triggerAllAppsButtonLongClick();
- mAllAppsTouchTriggered = true;
- };
- AssistStateManager assistStateManager = AssistStateManager.INSTANCE.get(mContext);
- if (DeviceConfigWrapper.get().getCustomLpaaThresholds()
- && assistStateManager.getLPNHDurationMillis().isPresent()) {
- mAllAppsButtonTouchDelayMs = assistStateManager.getLPNHDurationMillis().get();
- }
+ if (mAllAppsButtonContainer != null) {
+ mAllAppsButtonContainer.setUpCallbacks(callbacks);
}
- if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
- mTaskbarDivider.setOnLongClickListener(
- mControllerCallbacks.getTaskbarDividerLongClickListener());
- mTaskbarDivider.setOnTouchListener(
- mControllerCallbacks.getTaskbarDividerRightClickListener());
+ if (mTaskbarDividerContainer != null && callbacks.supportsDividerLongPress()) {
+ mTaskbarDividerContainer.setUpCallbacks(callbacks);
}
}
@@ -340,13 +280,13 @@
protected void updateHotseatItems(ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
int nextViewIndex = 0;
int numViewsAnimated = 0;
- boolean addedDividerForRecents = false;
+ mAddedDividerForRecents = false;
- if (mAllAppsButton != null) {
- removeView(mAllAppsButton);
+ if (mAllAppsButtonContainer != null) {
+ removeView(mAllAppsButtonContainer);
- if (mTaskbarDivider != null) {
- removeView(mTaskbarDivider);
+ if (mTaskbarDividerContainer != null) {
+ removeView(mTaskbarDividerContainer);
}
}
removeView(mQsb);
@@ -433,9 +373,9 @@
nextViewIndex++;
}
- if (mTaskbarDivider != null && !recentTasks.isEmpty()) {
- addView(mTaskbarDivider, nextViewIndex++);
- addedDividerForRecents = true;
+ if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
+ addView(mTaskbarDividerContainer, nextViewIndex++);
+ mAddedDividerForRecents = true;
}
// Add Recent/Running icons.
@@ -498,12 +438,14 @@
removeAndRecycle(getChildAt(nextViewIndex));
}
- if (mAllAppsButton != null) {
- addView(mAllAppsButton, mIsRtl ? getChildCount() : 0);
+ if (mAllAppsButtonContainer != null) {
+ addView(mAllAppsButtonContainer, mIsRtl ? hotseatItemInfos.length : 0);
// If there are no recent tasks, add divider after All Apps (unless it's the only view).
- if (!addedDividerForRecents && mTaskbarDivider != null && getChildCount() > 1) {
- addView(mTaskbarDivider, mIsRtl ? (getChildCount() - 1) : 1);
+ if (!mAddedDividerForRecents
+ && mTaskbarDividerContainer != null
+ && getChildCount() > 1) {
+ addView(mTaskbarDividerContainer, mIsRtl ? (getChildCount() - 1) : 1);
}
}
if (mActivityContext.getDeviceProfile().isQsbInline) {
@@ -631,7 +573,7 @@
int qsbTop = (bottom - top - deviceProfile.hotseatQsbHeight) / 2;
int qsbBottom = qsbTop + deviceProfile.hotseatQsbHeight;
child.layout(qsbStart, qsbTop, qsbEnd, qsbBottom);
- } else if (child == mTaskbarDivider) {
+ } else if (child == mTaskbarDividerContainer) {
iconEnd += mItemMarginLeftRight;
int iconStart = iconEnd - mIconTouchSize;
child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
@@ -669,8 +611,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;
}
/**
@@ -709,16 +663,24 @@
* Returns the all apps button in the taskbar.
*/
@Nullable
- public View getAllAppsButtonView() {
- return mAllAppsButton;
+ public TaskbarAllAppsButtonContainer getAllAppsButtonContainer() {
+ return mAllAppsButtonContainer;
}
/**
* Returns the taskbar divider in the taskbar.
*/
@Nullable
- public View getTaskbarDividerView() {
- return mTaskbarDivider;
+ public TaskbarDividerContainer getTaskbarDividerViewContainer() {
+ return mTaskbarDividerContainer;
+ }
+
+ /**
+ * Returns whether the divider is between Hotseat icons and Recents,
+ * instead of between All Apps button and Hotseat.
+ */
+ public boolean isDividerForRecents() {
+ return mAddedDividerForRecents;
}
/**
@@ -806,48 +768,6 @@
}
}
}
- return mAllAppsButton;
- }
-
- private boolean onAllAppsButtonTouch(View view, MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mAllAppsTouchTriggered = false;
- MAIN_EXECUTOR.getHandler().postDelayed(
- mAllAppsTouchRunnable, mAllAppsButtonTouchDelayMs);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- cancelAllAppsButtonTouch();
- }
- return false;
- }
-
- private void cancelAllAppsButtonTouch() {
- MAIN_EXECUTOR.getHandler().removeCallbacks(mAllAppsTouchRunnable);
- // ACTION_UP is first triggered, then click listener / long-click listener is triggered on
- // the next frame, so we need to post twice and delay the reset.
- if (mAllAppsButton != null) {
- mAllAppsButton.post(() -> {
- mAllAppsButton.post(() -> {
- mAllAppsTouchTriggered = false;
- });
- });
- }
- }
-
- private void onAllAppsButtonClick(View view) {
- if (!mAllAppsTouchTriggered) {
- mControllerCallbacks.triggerAllAppsButtonClick(view);
- }
- }
-
- // Handle long click from Switch Access and Voice Access
- private boolean onAllAppsButtonLongClick(View view) {
- if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mAllAppsTouchRunnable)
- && !mAllAppsTouchTriggered) {
- mControllerCallbacks.triggerAllAppsButtonLongClick();
- }
- return true;
+ return mAllAppsButtonContainer;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index e6cac2f..5ec00ac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -28,7 +28,7 @@
import com.android.internal.jank.Cuj;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
/**
* Callbacks for {@link TaskbarView} to interact with its controller.
@@ -51,7 +51,7 @@
}
/** Trigger All Apps button click action. */
- protected void triggerAllAppsButtonClick(View v) {
+ public void triggerAllAppsButtonClick(View v) {
InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS,
/* tag= */ "TASKBAR_BUTTON");
mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
@@ -59,7 +59,7 @@
}
/** Trigger All Apps button long click action. */
- protected void triggerAllAppsButtonLongClick() {
+ public void triggerAllAppsButtonLongClick() {
mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS);
}
@@ -74,6 +74,11 @@
};
}
+ /** Check to see if we support long press on taskbar divider */
+ public boolean supportsDividerLongPress() {
+ return !mActivity.isThreeButtonNav();
+ }
+
public View.OnTouchListener getTaskbarDividerRightClickListener() {
return (v, event) -> {
if (event.isFromSource(InputDevice.SOURCE_MOUSE)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index ffa4819..292b9ed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -72,7 +72,6 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
@@ -96,7 +95,15 @@
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;
+
+ /** Only used for animation purposes, to position the divider between two item indices. */
+ public static final float DIVIDER_VIEW_POSITION_OFFSET = 0.5f;
+
+ /** Used if an unexpected edge case is hit in {@link #getPositionInHotseat}. */
+ private static final float ERROR_POSITION_IN_HOTSEAT_NOT_FOUND = -100;
private static boolean sEnableModelLoadingForTests = true;
@@ -142,6 +149,7 @@
private Runnable mOnControllerPreCreateCallback = NO_OP;
// Stored here as signals to determine if the mIconAlignController needs to be recreated.
+ private boolean mIsIconAlignedWithHotseat;
private boolean mIsHotseatIconOnTopWhenAligned;
private boolean mIsStashed;
@@ -198,7 +206,8 @@
mModelCallbacks.init(controllers);
if (mActivity.isUserSetupComplete() && sEnableModelLoadingForTests) {
// Only load the callbacks if user setup is completed
- LauncherAppState.getInstance(mActivity).getModel().addCallbacksAndLoad(mModelCallbacks);
+ controllers.runAfterInit(() -> LauncherAppState.getInstance(mActivity).getModel()
+ .addCallbacksAndLoad(mModelCallbacks));
}
mTaskbarNavButtonTranslationY =
controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY();
@@ -210,8 +219,8 @@
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// This gets modified in NavbarButtonsViewController, but the initial value it reads
// may be incorrect since it's state gets destroyed on taskbar recreate, so reset here
- mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN)
- .animateToValue(mActivity.isPhoneButtonNavMode() ? 0 : 1).start();
+ mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN).setValue(
+ mActivity.isPhoneMode() ? 0 : 1);
}
if (enableTaskbarPinning()) {
mTaskbarView.addOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
@@ -272,6 +281,10 @@
OneShotPreDrawListener.add(mTaskbarView, listener);
}
+ public Rect getIconLayoutVisualBounds() {
+ return mTaskbarView.getIconLayoutVisualBounds();
+ }
+
public Rect getIconLayoutBounds() {
return mTaskbarView.getIconLayoutBounds();
}
@@ -286,7 +299,7 @@
@Nullable
public View getAllAppsButtonView() {
- return mTaskbarView.getAllAppsButtonView();
+ return mTaskbarView.getAllAppsButtonContainer();
}
public AnimatedFloat getTaskbarIconScaleForStash() {
@@ -353,9 +366,9 @@
View[] iconViews = mTaskbarView.getIconViews();
float scale = mTaskbarIconTranslationXForPinning.value;
float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
- mTaskbarView.getAllAppsButtonTranslationXOffset(true));
+ mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(true));
float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
- mTaskbarView.getAllAppsButtonTranslationXOffset(false));
+ mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(false));
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
persistentTaskbarAllAppsOffset);
@@ -370,7 +383,7 @@
}
if (mActivity.isThreeButtonNav()) {
- ((IconButtonView) mTaskbarView.getAllAppsButtonView())
+ mTaskbarView.getAllAppsButtonContainer()
.setTranslationXForTaskbarAllAppsIcon(allAppIconTranslateRange);
return;
}
@@ -395,8 +408,8 @@
-finalMarginScale * (iconIndex - halfIconCount));
}
- if (iconView.equals(mTaskbarView.getAllAppsButtonView())) {
- ((IconButtonView) iconView).setTranslationXForTaskbarAllAppsIcon(
+ if (iconView.equals(mTaskbarView.getAllAppsButtonContainer())) {
+ mTaskbarView.getAllAppsButtonContainer().setTranslationXForTaskbarAllAppsIcon(
allAppIconTranslateRange);
}
}
@@ -462,14 +475,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);
@@ -524,7 +537,7 @@
}
public View getTaskbarDividerView() {
- return mTaskbarView.getTaskbarDividerView();
+ return mTaskbarView.getTaskbarDividerViewContainer();
}
/**
@@ -675,15 +688,17 @@
mIconAlignControllerLazy = null;
return;
}
-
boolean isHotseatIconOnTopWhenAligned =
mControllers.uiController.isHotseatIconOnTopWhenAligned();
+ boolean isIconAlignedWithHotseat = mControllers.uiController.isIconAlignedWithHotseat();
boolean isStashed = mControllers.taskbarStashController.isStashed();
- // Re-create animation when mIsHotseatIconOnTopWhenAligned or mIsStashed changes.
+ // Re-create animation when any of these values change.
if (mIconAlignControllerLazy == null
|| mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned
+ || mIsIconAlignedWithHotseat != isIconAlignedWithHotseat
|| mIsStashed != isStashed) {
mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned;
+ mIsIconAlignedWithHotseat = isIconAlignedWithHotseat;
mIsStashed = isStashed;
mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
}
@@ -735,17 +750,22 @@
? mTransientTaskbarDp.taskbarBottomMargin
: mPersistentTaskbarDp.taskbarBottomMargin;
+ int firstRecentTaskIndex = -1;
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
- boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonView();
- boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerView();
+ boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer();
+ boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerViewContainer();
+ boolean isRecentTask = child.getTag() instanceof GroupTask;
+ // TODO(b/343522351): show recents on the home screen.
+ final boolean isRecentsInHotseat = false;
if (!mIsHotseatIconOnTopWhenAligned) {
// When going to home, the EMPHASIZED interpolator in TaskbarLauncherStateController
// plays iconAlignment to 1 really fast, therefore moving the fading towards the end
// to avoid icons disappearing rather than fading out visually.
setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f));
} else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get())
- || (isTaskbarDividerView && enableTaskbarPinning())) {
+ || (isTaskbarDividerView && enableTaskbarPinning())
+ || (isRecentTask && !isRecentsInHotseat)) {
if (!isToHome
&& mIsHotseatIconOnTopWhenAligned
&& mIsStashed) {
@@ -806,25 +826,17 @@
continue;
}
- float positionInHotseat;
- if (isAllAppsButton) {
- // Note that there is no All Apps button in the hotseat,
- // this position is only used as its convenient for animation purposes.
- positionInHotseat = Utilities.isRtl(child.getResources())
- ? taskbarDp.numShownHotseatIcons
- : -1;
- } else if (isTaskbarDividerView) {
- // Note that there is no taskbar divider view in the hotseat,
- // this position is only used as its convenient for animation purposes.
- positionInHotseat = Utilities.isRtl(child.getResources())
- ? taskbarDp.numShownHotseatIcons - 0.5f
- : -0.5f;
- } else if (child.getTag() instanceof ItemInfo) {
- positionInHotseat = ((ItemInfo) child.getTag()).screenId;
- } else {
- Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child);
- continue;
+ int recentTaskIndex = -1;
+ if (isRecentTask) {
+ if (firstRecentTaskIndex < 0) {
+ firstRecentTaskIndex = i;
+ }
+ recentTaskIndex = i - firstRecentTaskIndex;
}
+ float positionInHotseat = getPositionInHotseat(taskbarDp.numShownHotseatIcons, child,
+ mIsRtl, isAllAppsButton, isTaskbarDividerView,
+ mTaskbarView.isDividerForRecents(), recentTaskIndex);
+ if (positionInHotseat == ERROR_POSITION_IN_HOTSEAT_NOT_FOUND) continue;
float hotseatAdjustedBorderSpace =
launcherDp.getHotseatAdjustedBorderSpaceForBubbleBar(child.getContext());
@@ -860,6 +872,58 @@
return controller;
}
+ /**
+ * Returns the index of the given child relative to its position in hotseat.
+ * Examples:
+ * -1 is the item before the first hotseat item.
+ * -0.5 is between those (e.g. for the divider).
+ * {@link #ERROR_POSITION_IN_HOTSEAT_NOT_FOUND} if there's no calculation relative to hotseat.
+ */
+ @VisibleForTesting
+ float getPositionInHotseat(int numShownHotseatIcons, View child, boolean isRtl,
+ boolean isAllAppsButton, boolean isTaskbarDividerView, boolean isDividerForRecents,
+ int recentTaskIndex) {
+ float positionInHotseat;
+ // Note that there is no All Apps button in the hotseat,
+ // this position is only used as it's convenient for animation purposes.
+ float allAppsButtonPositionInHotseat = isRtl
+ // Right after all hotseat items.
+ // [HHHHHH]|[>A<]
+ ? numShownHotseatIcons
+ // Right before all hotseat items.
+ // [>A<]|[HHHHHH]
+ : -1;
+ // Note that there are no recent tasks in the hotseat,
+ // this position is only used as it's convenient for animation purposes.
+ float firstRecentTaskPositionInHotseat = isRtl
+ // After all hotseat icons and All Apps button.
+ // [HHHHHH][A]|[>R<R]
+ ? numShownHotseatIcons + 1
+ // Right after all hotseat items.
+ // [A][HHHHHH]|[>R<R]
+ : numShownHotseatIcons;
+ if (isAllAppsButton) {
+ positionInHotseat = allAppsButtonPositionInHotseat;
+ } else if (isTaskbarDividerView) {
+ // Note that there is no taskbar divider view in the hotseat,
+ // this position is only used as it's convenient for animation purposes.
+ float relativePosition = isDividerForRecents
+ ? firstRecentTaskPositionInHotseat
+ : allAppsButtonPositionInHotseat;
+ positionInHotseat = relativePosition > 0
+ ? relativePosition - DIVIDER_VIEW_POSITION_OFFSET
+ : relativePosition + DIVIDER_VIEW_POSITION_OFFSET;
+ } else if (child.getTag() instanceof ItemInfo) {
+ positionInHotseat = ((ItemInfo) child.getTag()).screenId;
+ } else if (recentTaskIndex >= 0) {
+ positionInHotseat = firstRecentTaskPositionInHotseat + recentTaskIndex;
+ } else {
+ Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child);
+ return ERROR_POSITION_IN_HOTSEAT_NOT_FOUND;
+ }
+ return positionInHotseat;
+ }
+
private boolean bubbleBarHasBubbles() {
return mControllers.bubbleControllers.isPresent()
&& mControllers.bubbleControllers.get().bubbleBarViewController.hasBubbles();
@@ -944,7 +1008,6 @@
"ALPHA_INDEX_RECENTS_DISABLED",
"ALPHA_INDEX_NOTIFICATION_EXPANDED",
"ALPHA_INDEX_ASSISTANT_INVOKED",
- "ALPHA_INDEX_IME_BUTTON_NAV",
"ALPHA_INDEX_SMALL_SCREEN");
mModelCallbacks.dumpLogs(prefix + "\t", pw);
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/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 90ac872..f5ac66f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar.allapps;
import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL;
import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL;
@@ -193,14 +192,12 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mActivityContext.addOnDeviceProfileChangeListener(this);
- if (enablePredictiveBackGesture()) {
- mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
- mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
- OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
- if (dispatcher != null) {
- dispatcher.registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
- }
+ mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
+ mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
+ OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+ if (dispatcher != null) {
+ dispatcher.registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
}
}
@@ -208,13 +205,11 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mActivityContext.removeOnDeviceProfileChangeListener(this);
- if (enablePredictiveBackGesture()) {
- mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
- mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
- OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
- if (dispatcher != null) {
- dispatcher.unregisterOnBackInvokedCallback(this);
- }
+ mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
+ mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
+ OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+ if (dispatcher != null) {
+ dispatcher.unregisterOnBackInvokedCallback(this);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 25939e1..f08318e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -71,6 +71,27 @@
}
}
+ /**
+ * Scale of the background in the x direction. Pivot is at the left edge if [anchorLeft] is
+ * `true` and at the right edge if it is `false`
+ */
+ var scaleX: Float = 1f
+ set(value) {
+ if (field != value) {
+ field = value
+ invalidateSelf()
+ }
+ }
+
+ /** Scale of the background in the y direction. Pivot is at the bottom edge. */
+ var scaleY: Float = 1f
+ set(value) {
+ if (field != value) {
+ field = value
+ invalidateSelf()
+ }
+ }
+
init {
val res = context.resources
// configure fill paint
@@ -123,13 +144,17 @@
)
// Create background path
val backgroundPath = Path()
- val topOffset = backgroundHeight - bounds.height().toFloat()
+ val scaledBackgroundHeight = backgroundHeight * scaleY
+ val scaledWidth = width * scaleX
+ val topOffset = scaledBackgroundHeight - bounds.height().toFloat()
val radius = backgroundHeight / 2f
- val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width)
- val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat())
- val top = bounds.top - topOffset + arrowVisibleHeight
- val bottom = bounds.top + bounds.height().toFloat()
+ val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - scaledWidth)
+ val right = bounds.left + (if (anchorLeft) scaledWidth else bounds.width().toFloat())
+ // Calculate top with scaled heights for background and arrow to align with stash handle
+ val top = bounds.bottom - scaledBackgroundHeight + getScaledArrowVisibleHeight()
+ val bottom = bounds.bottom.toFloat()
+
backgroundPath.addRoundRect(left, top, right, bottom, radius, radius, Path.Direction.CW)
addArrowPathIfNeeded(backgroundPath, topOffset)
@@ -142,19 +167,20 @@
private fun addArrowPathIfNeeded(sourcePath: Path, topOffset: Float) {
if (!showingArrow || arrowHeightFraction <= 0) return
val arrowPath = Path()
+ val scaledHeight = getScaledArrowHeight()
RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
arrowWidth,
- arrowHeight,
+ scaledHeight,
arrowTipRadius,
arrowPath
)
// flip it horizontally
val pathTransform = Matrix()
- pathTransform.setRotate(180f, arrowWidth * 0.5f, arrowHeight * 0.5f)
+ pathTransform.setRotate(180f, arrowWidth * 0.5f, scaledHeight * 0.5f)
arrowPath.transform(pathTransform)
// shift to arrow position
val arrowStart = bounds.left + arrowPositionX - (arrowWidth / 2f)
- val arrowTop = (1 - arrowHeightFraction) * arrowVisibleHeight - topOffset
+ val arrowTop = (1 - arrowHeightFraction) * getScaledArrowVisibleHeight() - topOffset
arrowPath.offset(arrowStart, arrowTop)
// union with rectangle
sourcePath.op(arrowPath, Path.Op.UNION)
@@ -183,6 +209,7 @@
fun setBackgroundHeight(newHeight: Float) {
backgroundHeight = newHeight
+ invalidateSelf()
}
/**
@@ -199,6 +226,14 @@
invalidateSelf()
}
+ private fun getScaledArrowHeight(): Float {
+ return arrowHeight * scaleY
+ }
+
+ private fun getScaledArrowVisibleHeight(): Float {
+ return max(0f, getScaledArrowHeight() - (arrowHeight - arrowVisibleHeight))
+ }
+
companion object {
private const val DARK_THEME_STROKE_ALPHA = 51
private const val LIGHT_THEME_STROKE_ALPHA = 41
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 33d8a84..d70a317 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -41,10 +41,10 @@
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.wm.shell.Flags;
import com.android.wm.shell.bubbles.IBubblesListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
-import com.android.wm.shell.common.bubbles.RemovedBubble;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
+import com.android.wm.shell.shared.bubbles.RemovedBubble;
import java.util.ArrayList;
import java.util.List;
@@ -168,10 +168,6 @@
mBarView = bubbleView; // Need the view for inflating bubble views.
mSystemUiProxy = SystemUiProxy.INSTANCE.get(context);
-
- if (sBubbleBarEnabled) {
- mSystemUiProxy.setBubblesListener(this);
- }
}
public void onDestroy() {
@@ -197,6 +193,10 @@
mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse(
key -> setSelectedBubbleInternal(mBubbles.get(key)));
mBubbleBarViewController.setBoundsChangeListener(this::onBubbleBarBoundsChanged);
+
+ if (sBubbleBarEnabled) {
+ mSystemUiProxy.setBubblesListener(this);
+ }
});
}
@@ -286,9 +286,10 @@
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);
@@ -495,6 +496,11 @@
() -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation));
}
+ /** Notifies WMShell to show the expanded view. */
+ void showExpandedView() {
+ mSystemUiProxy.showExpandedView();
+ }
+
//
// Loading data for the bubbles
//
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
index 39d1ed7..7a32ef1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
@@ -17,7 +17,7 @@
import android.graphics.Bitmap
import android.graphics.Path
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
/** An entity in the bubble bar. */
sealed class BubbleBarItem(open var key: String, open var view: BubbleView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index a6b0860..9c34307 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -28,8 +28,8 @@
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
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
/**
* Controller to manage pinning bubble bar to left or right when dragging starts from the bubble bar
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 4d0cad2..ae88f1d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -48,7 +48,7 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.taskbar.bubbles.animation.BubbleAnimator;
import com.android.launcher3.util.DisplayController;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -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
@@ -189,6 +187,9 @@
private BubbleView mDismissedByDragBubbleView;
private float mAlphaDuringDrag = 1f;
+ /** Additional translation in the y direction that is applied to each bubble */
+ private float mBubbleOffsetY;
+
private Controller mController;
private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED;
@@ -207,7 +208,6 @@
public BubbleBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- setAlpha(0);
setVisibility(INVISIBLE);
mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
mBubbleBarPadding = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
@@ -246,7 +246,7 @@
if (mIsBarExpanded && mSelectedBubbleView != null) {
mSelectedBubbleView.markSeen();
}
- updateWidth();
+ updateLayoutParams();
},
/* onUpdate= */ animator -> {
updateBubblesLayoutProperties(mBubbleBarLocation);
@@ -308,6 +308,46 @@
}
/**
+ * Set scale for bubble bar background in x direction
+ */
+ public void setBackgroundScaleX(float scaleX) {
+ mBubbleBarBackground.setScaleX(scaleX);
+ }
+
+ /**
+ * Set scale for bubble bar background in y direction
+ */
+ public void setBackgroundScaleY(float scaleY) {
+ mBubbleBarBackground.setScaleY(scaleY);
+ }
+
+ /**
+ * Set alpha for bubble views
+ */
+ public void setBubbleAlpha(float alpha) {
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setAlpha(alpha);
+ }
+ }
+
+ /**
+ * Set alpha for bar background
+ */
+ public void setBackgroundAlpha(float alpha) {
+ mBubbleBarBackground.setAlpha((int) (255 * alpha));
+ }
+
+ /**
+ * Sets offset of each bubble view in the y direction from the base position in the bar.
+ */
+ public void setBubbleOffsetY(float offsetY) {
+ mBubbleOffsetY = offsetY;
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setTranslationY(getBubbleTranslationY());
+ }
+ }
+
+ /**
* Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders.
*
* @param newIconSize new icon size
@@ -324,7 +364,7 @@
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
- childView.setScaleY(mIconScale);
+ childView.setScaleX(mIconScale);
childView.setScaleY(mIconScale);
FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
params.height = (int) mIconSize;
@@ -649,7 +689,9 @@
}
setAlphaDuringBubbleDrag(1f);
setTranslationX(0f);
- setAlpha(1f);
+ if (getBubbleChildCount() > 0) {
+ setAlpha(1f);
+ }
}
/**
@@ -661,13 +703,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;
}
/**
@@ -702,16 +756,6 @@
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,
@@ -731,7 +775,7 @@
@Override
public void onAnimationEnd() {
- updateWidth();
+ updateLayoutParams();
mBubbleAnimator = null;
}
@@ -756,7 +800,8 @@
}
/** Add a new bubble and remove an old bubble from the bubble bar. */
- public void addBubbleAndRemoveBubble(BubbleView addedBubble, BubbleView 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();
@@ -767,6 +812,9 @@
removeView(removedBubble);
int index = addingOverflow ? getChildCount() : 0;
addView(addedBubble, index, lp);
+ if (onEndRunnable != null) {
+ onEndRunnable.run();
+ }
return;
}
int index = addingOverflow ? getChildCount() : 0;
@@ -788,8 +836,11 @@
@Override
public void onAnimationEnd() {
removeView(removedBubble);
- updateWidth();
+ updateLayoutParams();
mBubbleAnimator = null;
+ if (onEndRunnable != null) {
+ onEndRunnable.run();
+ }
}
@Override
@@ -817,7 +868,7 @@
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
- updateWidth();
+ updateLayoutParams();
updateBubbleAccessibilityStates();
updateContentDescription();
}
@@ -881,7 +932,7 @@
mSelectedBubbleView = null;
mBubbleBarBackground.showArrow(false);
}
- updateWidth();
+ updateLayoutParams();
updateBubbleAccessibilityStates();
updateContentDescription();
mDismissedByDragBubbleView = null;
@@ -931,12 +982,6 @@
}
}
- private void updateWidth() {
- LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
- setLayoutParams(lp);
- }
-
private void updateLayoutParams() {
LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
lp.height = (int) getBubbleBarExpandedHeight();
@@ -965,10 +1010,7 @@
final float expandedWidth = expandedWidth();
final float collapsedWidth = collapsedWidth();
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
- final float ty = bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift();
+ final float ty = getBubbleTranslationY();
final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl());
// elevation state is opposite to widthState - when expanded all icons are flat
float elevationState = (1 - widthState);
@@ -1015,7 +1057,7 @@
// where the bubble will end up when the animation ends
final float targetX = expandedX + expandedBarShift;
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
- bv.setAlpha(1);
+ bv.setVisibility(VISIBLE);
} else {
// If bar is on the right, account for bubble bar expanding and shifting left
final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
@@ -1025,9 +1067,9 @@
// the overflow.
if (widthState == 0) {
if (bv.isOverflow() || i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
- bv.setAlpha(0);
+ bv.setVisibility(INVISIBLE);
} else {
- bv.setAlpha(1);
+ bv.setVisibility(VISIBLE);
}
}
}
@@ -1102,6 +1144,13 @@
return mBubbleBarPadding + translationX - getScaleIconShift();
}
+ private float getBubbleTranslationY() {
+ 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
+ return mBubbleOffsetY + bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift();
+ }
+
/**
* Reorders the views to match the provided list.
*/
@@ -1280,6 +1329,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
@@ -1296,7 +1352,10 @@
return totalIconSize + totalSpace + horizontalPadding;
}
- private float collapsedWidth() {
+ /**
+ * Get width of the bubble bar if it is collapsed
+ */
+ float collapsedWidth() {
final int bubbleChildCount = getBubbleChildCount();
final float horizontalPadding = 2 * mBubbleBarPadding;
// If there are more than 2 bubbles, the first 2 should be visible when collapsed,
@@ -1307,7 +1366,7 @@
}
/** Returns the child count excluding the overflow if it's present. */
- private int getBubbleChildCount() {
+ int getBubbleChildCount() {
return hasOverflow() ? getChildCount() - 1 : getChildCount();
}
@@ -1325,7 +1384,7 @@
* touch bounds.
*/
public boolean isEventOverAnyItem(MotionEvent ev) {
- if (getVisibility() == View.VISIBLE) {
+ if (getVisibility() == VISIBLE) {
getBoundsOnScreen(mTempRect);
return mTempRect.contains((int) ev.getX(), (int) ev.getY());
}
@@ -1334,9 +1393,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;
@@ -1344,11 +1401,6 @@
return super.onInterceptTouchEvent(ev);
}
- /** Whether a new bubble is currently animating. */
- public boolean isAnimatingNewBubble() {
- return mIsAnimatingNewBubble;
- }
-
private boolean hasOverflow() {
// Overflow is always the last bubble
View lastChild = getChildAt(getChildCount() - 1);
@@ -1473,15 +1525,15 @@
pw.println("BubbleBarView state:");
pw.println(" visibility: " + getVisibility());
pw.println(" alpha: " + getAlpha());
- pw.println(" translation Y: " + getTranslationY());
- pw.println(" bubbles in bar (childCount = " + getChildCount() + ")");
+ pw.println(" translationY: " + getTranslationY());
+ pw.println(" childCount: " + getChildCount());
+ pw.println(" hasOverflow: " + hasOverflow());
for (BubbleView bubbleView: getBubbles()) {
BubbleBarItem bubble = bubbleView.getBubble();
String key = bubble == null ? "null" : bubble.getKey();
pw.println(" bubble key: " + key);
}
pw.println(" isExpanded: " + isExpanded());
- pw.println(" mIsAnimatingNewBubble: " + mIsAnimatingNewBubble);
if (mBubbleAnimator != null) {
pw.println(" mBubbleAnimator.isRunning(): " + mBubbleAnimator.isRunning());
pw.println(" mBubbleAnimator is null");
@@ -1506,8 +1558,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 83123b5..ed08de5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,6 +18,8 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
@@ -34,6 +36,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarInsetsController;
@@ -43,7 +46,7 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.SystemUiProxy;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.io.PrintWriter;
import java.util.List;
@@ -72,6 +75,7 @@
private BubbleDragController mBubbleDragController;
private TaskbarStashController mTaskbarStashController;
private TaskbarInsetsController mTaskbarInsetsController;
+ private TaskbarViewPropertiesProvider mTaskbarViewPropertiesProvider;
private View.OnClickListener mBubbleClickListener;
private View.OnClickListener mBubbleBarClickListener;
private BubbleView.Controller mBubbleViewController;
@@ -79,12 +83,24 @@
// These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
private final MultiValueAlpha mBubbleBarAlpha;
- private final AnimatedFloat mBubbleBarScale = new AnimatedFloat(this::updateScale);
+ private final AnimatedFloat mBubbleBarBubbleAlpha = new AnimatedFloat(this::updateBubbleAlpha);
+ private final AnimatedFloat mBubbleBarBackgroundAlpha = new AnimatedFloat(
+ this::updateBackgroundAlpha);
+ private final AnimatedFloat mBubbleBarScaleX = new AnimatedFloat(this::updateScaleX);
+ private final AnimatedFloat mBubbleBarScaleY = new AnimatedFloat(this::updateScaleY);
+ private final AnimatedFloat mBubbleBarBackgroundScaleX = new AnimatedFloat(
+ this::updateBackgroundScaleX);
+ private final AnimatedFloat mBubbleBarBackgroundScaleY = new AnimatedFloat(
+ this::updateBackgroundScaleY);
private final AnimatedFloat mBubbleBarTranslationY = new AnimatedFloat(
this::updateTranslationY);
+ private final AnimatedFloat mBubbleOffsetY = new AnimatedFloat(
+ this::updateBubbleOffsetY);
// Modified when swipe up is happening on the bubble bar or task bar.
private float mBubbleBarSwipeUpTranslationY;
+ // Modified when bubble bar is springing back into the stash handle.
+ private float mBubbleBarStashTranslationY;
// Whether the bar is hidden for a sysui state.
private boolean mHiddenForSysui;
@@ -110,17 +126,21 @@
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);
+ mBubbleBarViewAnimator = new BubbleBarViewAnimator(
+ mBarView, mBubbleStashController, mBubbleBarController::showExpandedView);
+ mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
onBubbleBarConfigurationChanged(/* animate= */ false);
mActivity.addOnDeviceProfileChangeListener(
dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
- mBubbleBarScale.updateValue(1f);
+ mBubbleBarScaleY.updateValue(1f);
mBubbleClickListener = v -> onBubbleClicked((BubbleView) v);
mBubbleBarClickListener = v -> expandBubbleBar();
mBubbleDragController.setupBubbleBarView(mBarView);
@@ -140,8 +160,8 @@
}
@Override
- public void onBubbleBarTouchedWhileAnimating() {
- BubbleBarViewController.this.onBubbleBarTouchedWhileAnimating();
+ public void onBubbleBarTouched() {
+ BubbleBarViewController.this.onBubbleBarTouched();
}
@Override
@@ -202,9 +222,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() {
@@ -247,19 +270,68 @@
return mBubbleBarAlpha;
}
- public AnimatedFloat getBubbleBarScale() {
- return mBubbleBarScale;
+ public AnimatedFloat getBubbleBarBubbleAlpha() {
+ return mBubbleBarBubbleAlpha;
+ }
+
+ public AnimatedFloat getBubbleBarBackgroundAlpha() {
+ return mBubbleBarBackgroundAlpha;
+ }
+
+ public AnimatedFloat getBubbleBarScaleX() {
+ return mBubbleBarScaleX;
+ }
+
+ public AnimatedFloat getBubbleBarScaleY() {
+ return mBubbleBarScaleY;
+ }
+
+ public AnimatedFloat getBubbleBarBackgroundScaleX() {
+ return mBubbleBarBackgroundScaleX;
+ }
+
+ public AnimatedFloat getBubbleBarBackgroundScaleY() {
+ return mBubbleBarBackgroundScaleY;
}
public AnimatedFloat getBubbleBarTranslationY() {
return mBubbleBarTranslationY;
}
+ public AnimatedFloat getBubbleOffsetY() {
+ return mBubbleOffsetY;
+ }
+
+ public float getBubbleBarCollapsedWidth() {
+ return mBarView.collapsedWidth();
+ }
+
public float getBubbleBarCollapsedHeight() {
return mBarView.getBubbleBarCollapsedHeight();
}
/**
+ * @see BubbleBarView#getRelativePivotX()
+ */
+ public float getBubbleBarRelativePivotX() {
+ return mBarView.getRelativePivotX();
+ }
+
+ /**
+ * @see BubbleBarView#getRelativePivotY()
+ */
+ public float getBubbleBarRelativePivotY() {
+ return mBarView.getRelativePivotY();
+ }
+
+ /**
+ * @see BubbleBarView#setRelativePivot(float, float)
+ */
+ public void setBubbleBarRelativePivot(float x, float y) {
+ mBarView.setRelativePivot(x, y);
+ }
+
+ /**
* Whether the bubble bar is visible or not.
*/
public boolean isBubbleBarVisible() {
@@ -279,6 +351,14 @@
}
/**
+ * @return {@code true} if bubble bar is on the left edge of the screen, {@code false} if on
+ * the right
+ */
+ public boolean isBubbleBarOnLeft() {
+ return mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl());
+ }
+
+ /**
* Update bar {@link BubbleBarLocation}
*/
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
@@ -301,10 +381,22 @@
return mBarView.getBubbleBarBounds();
}
+ /** Checks that bubble bar is visible and that the motion event is within bounds. */
+ public boolean isEventOverBubbleBar(MotionEvent event) {
+ if (!isBubbleBarVisible()) return false;
+ final Rect bounds = getBubbleBarBounds();
+ final int bubbleBarTopOnScreen = mBarView.getRestingTopPositionOnScreen();
+ final float x = event.getX();
+ return event.getRawY() >= bubbleBarTopOnScreen && x >= bounds.left && x <= bounds.right;
+ }
+
/** Whether a new bubble is animating. */
public boolean isAnimatingNewBubble() {
- return mBarView.isAnimatingNewBubble()
- || (mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.hasAnimatingBubble());
+ 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. */
@@ -348,6 +440,7 @@
if (hidden) {
mBarView.setAlpha(0);
mBarView.setExpanded(false);
+ updatePersistentTaskbar(/* isBubbleBarExpanded = */ false);
}
mActivity.bubbleBarVisibilityChanged(!hidden);
}
@@ -453,20 +546,47 @@
updateTranslationY();
}
- private void updateTranslationY() {
- mBarView.setTranslationY(mBubbleBarTranslationY.value
- + mBubbleBarSwipeUpTranslationY);
+ /**
+ * Sets the translation of the bubble bar during the stash animation.
+ */
+ public void setTranslationYForStash(float transY) {
+ mBubbleBarStashTranslationY = transY;
+ updateTranslationY();
}
- /**
- * Applies scale properties for the entire bubble bar.
- */
- private void updateScale() {
- float scale = mBubbleBarScale.value;
+ private void updateTranslationY() {
+ mBarView.setTranslationY(mBubbleBarTranslationY.value + mBubbleBarSwipeUpTranslationY
+ + mBubbleBarStashTranslationY);
+ }
+
+ private void updateScaleX(float scale) {
mBarView.setScaleX(scale);
+ }
+
+ private void updateScaleY(float scale) {
mBarView.setScaleY(scale);
}
+ private void updateBackgroundScaleX(float scale) {
+ mBarView.setBackgroundScaleX(scale);
+ }
+
+ private void updateBackgroundScaleY(float scale) {
+ mBarView.setBackgroundScaleY(scale);
+ }
+
+ private void updateBubbleAlpha(float alpha) {
+ mBarView.setBubbleAlpha(alpha);
+ }
+
+ private void updateBubbleOffsetY(float transY) {
+ mBarView.setBubbleOffsetY(transY);
+ }
+
+ private void updateBackgroundAlpha(float alpha) {
+ mBarView.setBackgroundAlpha(alpha);
+ }
+
//
// Manipulating the specific bubble views in the bar
//
@@ -485,8 +605,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);
@@ -520,7 +642,8 @@
public void addOverflowAndRemoveBubble(BubbleBarBubble removedBubble) {
if (mOverflowAdded) return;
mOverflowAdded = true;
- mBarView.addBubbleAndRemoveBubble(mOverflowBubble.getView(), removedBubble.getView());
+ mBarView.addBubbleAndRemoveBubble(mOverflowBubble.getView(), removedBubble.getView(),
+ null /* onEndRunnable */);
mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
mOverflowBubble.getView().setController(mBubbleViewController);
removedBubble.getView().setController(null);
@@ -530,7 +653,8 @@
public void removeOverflowAndAddBubble(BubbleBarBubble addedBubble) {
if (!mOverflowAdded) return;
mOverflowAdded = false;
- mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), mOverflowBubble.getView());
+ mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), mOverflowBubble.getView(),
+ null /* onEndRunnable */);
addedBubble.getView().setOnClickListener(mBubbleClickListener);
addedBubble.getView().setController(mBubbleViewController);
mOverflowBubble.getView().setController(null);
@@ -568,9 +692,8 @@
public void animateBubbleNotification(BubbleBarBubble bubble, boolean isExpanding,
boolean isUpdate) {
boolean isInApp = mTaskbarStashController.isInApp();
- // if this is the first bubble, animate to the initial state. one bubble is the overflow
- // so check for at most 2 children.
- if (mBarView.getChildCount() <= 2 && !isUpdate) {
+ // if this is the first bubble, animate to the initial state.
+ if (mBarView.getBubbleChildCount() == 1 && !isUpdate) {
mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
return;
}
@@ -612,6 +735,7 @@
public void setExpanded(boolean isExpanded) {
if (isExpanded != mBarView.isExpanded()) {
mBarView.setExpanded(isExpanded);
+ updatePersistentTaskbar(isExpanded);
if (!isExpanded) {
mSystemUiProxy.collapseBubbles();
} else {
@@ -622,12 +746,31 @@
}
}
+ 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 (isAnimatingNewBubble() && isExpanded) {
+ if (isNewBubbleAnimationRunningOrPending() && isExpanded) {
mBubbleBarViewAnimator.expandedWhileAnimating();
return;
}
@@ -729,6 +872,48 @@
}
/**
+ * Create an animator for showing or hiding bubbles when stashed state changes
+ *
+ * @param isStashed {@code true} when bubble bar should be stashed to the handle
+ */
+ public Animator createRevealAnimatorForStashChange(boolean isStashed) {
+ Rect stashedHandleBounds = new Rect();
+ mBubbleStashController.getHandleBounds(stashedHandleBounds);
+ int childCount = mBarView.getChildCount();
+ float newChildWidth = (float) stashedHandleBounds.width() / childCount;
+ AnimatorSet animatorSet = new AnimatorSet();
+ for (int i = 0; i < childCount; i++) {
+ BubbleView child = (BubbleView) mBarView.getChildAt(i);
+ animatorSet.play(
+ createRevealAnimForBubble(child, isStashed, stashedHandleBounds,
+ newChildWidth));
+ }
+ return animatorSet;
+ }
+
+ private Animator createRevealAnimForBubble(BubbleView bubbleView, boolean isStashed,
+ Rect stashedHandleBounds, float newWidth) {
+ Rect viewBounds = new Rect(0, 0, bubbleView.getWidth(), bubbleView.getHeight());
+
+ int viewCenterY = viewBounds.centerY();
+ int halfHandleHeight = stashedHandleBounds.height() / 2;
+ int widthDelta = Math.max(0, (int) (viewBounds.width() - newWidth) / 2);
+
+ Rect stashedViewBounds = new Rect(
+ viewBounds.left + widthDelta,
+ viewCenterY - halfHandleHeight,
+ viewBounds.right - widthDelta,
+ viewCenterY + halfHandleHeight
+ );
+
+ float viewRadius = 0f; // Use 0 to not clip the new message dot or the app icon
+ float stashedRadius = stashedViewBounds.height() / 2f;
+
+ return new RoundedRectRevealOutlineProvider(viewRadius, stashedRadius, viewBounds,
+ stashedViewBounds).createRevealAnimator(bubbleView, !isStashed, 0);
+ }
+
+ /**
* Listener to receive updates about bubble bar bounds changing
*/
public interface BubbleBarBoundsChangeListener {
@@ -749,10 +934,21 @@
pw.println(" mShouldShowEducation: " + mShouldShowEducation);
pw.println(" mBubbleBarTranslationY.value: " + mBubbleBarTranslationY.value);
pw.println(" mBubbleBarSwipeUpTranslationY: " + mBubbleBarSwipeUpTranslationY);
+ pw.println(" mOverflowAdded: " + mOverflowAdded);
if (mBarView != null) {
mBarView.dump(pw);
} else {
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 8478dc2..e00916a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -15,8 +15,15 @@
*/
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;
@@ -79,7 +86,20 @@
bubbleStashedHandleViewController.orElse(null),
taskbarControllers::runAfterInit
);
- bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this);
+ 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);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
index 8e9a2f6..12b1487 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
@@ -51,7 +51,7 @@
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;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
/**
* Loads the necessary info to populate / present a bubble (name, icon, shortcut).
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 5eebbd8..a459dd9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -29,8 +29,8 @@
import com.android.launcher3.R;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarDragLayer;
-import com.android.wm.shell.common.bubbles.DismissView;
-import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.shared.bubbles.DismissView;
+import com.android.wm.shell.shared.magnetictarget.MagnetizedObject;
/**
* Controls dismiss view presentation for the bubble bar dismiss functionality.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
index 6c3f0d8..a8002a5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
@@ -18,7 +18,7 @@
package com.android.launcher3.taskbar.bubbles
import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.DismissView
+import com.android.wm.shell.shared.bubbles.DismissView
/**
* Dismiss view is shared from WMShell. It requires setup with local resources.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 7aed2d2..adaba7a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -29,8 +29,8 @@
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import com.android.launcher3.R;
-import com.android.wm.shell.common.bubbles.DismissCircleView;
-import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.shared.bubbles.DismissCircleView;
+import com.android.wm.shell.shared.bubbles.DismissView;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
/**
@@ -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/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 656a266..42bd197 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -27,8 +27,8 @@
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.wm.shell.common.bubbles.BaseBubblePinController.LocationChangeListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController.LocationChangeListener;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
/**
* Controls bubble bar drag interactions.
@@ -77,6 +77,8 @@
private BubbleBarPinController mBubbleBarPinController;
private BubblePinController mBubblePinController;
+ private boolean mIsDragging;
+
public BubbleDragController(TaskbarActivityContext activity) {
mActivity = activity;
}
@@ -240,6 +242,16 @@
});
}
+ /** Whether there is an item being dragged or not. */
+ public boolean isDragging() {
+ return mIsDragging;
+ }
+
+ /** Sets whether something is being dragged or not. */
+ public void setIsDragging(boolean isDragging) {
+ mIsDragging = isDragging;
+ }
+
/**
* Bubble touch listener for handling a single bubble view or bubble bar view while dragging.
* The dragging starts after "shorter" long click (the long click duration might change):
@@ -436,6 +448,7 @@
private void startDragging(@NonNull View view) {
onDragStart();
+ BubbleDragController.this.setIsDragging(true);
mActivity.setTaskbarWindowFullscreen(true);
mAnimator = new BubbleDragAnimator(view);
mAnimator.animateFocused();
@@ -452,6 +465,7 @@
}
private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {
+ BubbleDragController.this.setIsDragging(false);
Runnable onComplete = () -> {
mActivity.setTaskbarWindowFullscreen(false);
cleanUp(view);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
index 1341b53..af1666f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
@@ -28,8 +28,8 @@
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
+import com.android.wm.shell.shared.bubbles.BaseBubblePinController
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
/** Controller to manage pinning bubble bar to left or right when dragging starts from a bubble */
class BubblePinController(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 8158fe7..3640c3b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -21,6 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -28,6 +29,7 @@
import android.view.View;
import android.view.ViewOutlineProvider;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
@@ -37,9 +39,9 @@
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
/**
* Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -49,23 +51,29 @@
private final TaskbarActivityContext mActivity;
private final StashedHandleView mStashedHandleView;
private final MultiValueAlpha mStashedHandleAlpha;
+ private float mTranslationForSwipeY;
+ private float mTranslationForStashY;
// Initialized in init.
private BubbleBarViewController mBarViewController;
private BubbleStashController mBubbleStashController;
private RegionSamplingHelper mRegionSamplingHelper;
- private int mBarSize;
- private int mStashedTaskbarHeight;
+ // Height of the area for the stash handle. Handle will be drawn in the center of this.
+ // This is also the area where touch is handled on the handle.
+ private int mStashedBubbleBarHeight;
private int mStashedHandleWidth;
private int mStashedHandleHeight;
- // The bounds we want to clip to in the settled state when showing the stashed handle.
+ // The bounds of the stashed handle in settled state.
private final Rect mStashedHandleBounds = new Rect();
+ private float mStashedHandleRadius;
// When the reveal animation is cancelled, we can assume it's about to create a new animation,
// which should start off at the same point the cancelled one left off.
private float mStartProgressForNextRevealAnim;
- private boolean mWasLastRevealAnimReversed;
+ // Use a nullable boolean to handle initial case where the last animation direction is not known
+ @Nullable
+ private Boolean mWasLastRevealAnimReversed = null;
// XXX: if there are more of these maybe do state flags instead
private boolean mHiddenForSysui;
@@ -77,6 +85,7 @@
mActivity = activity;
mStashedHandleView = stashedHandleView;
mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
+ mStashedHandleAlpha.setUpdateVisibility(true);
}
/** Initialize controller. */
@@ -84,26 +93,31 @@
mBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleStashController = bubbleControllers.bubbleStashController;
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
mStashedHandleHeight = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_handle_height);
mStashedHandleWidth = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_handle_width);
- mBarSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
- final int bottomMargin = resources.getDimensionPixelSize(
- R.dimen.transient_taskbar_bottom_margin);
- mStashedHandleView.getLayoutParams().height = mBarSize + bottomMargin;
+ int barSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
+ // Use the max translation for bubble bar whether it is on the home screen or in app.
+ // Use values directly from device profile to avoid referencing other bubble controllers
+ // during init flow.
+ int maxTy = Math.max(deviceProfile.hotseatBarBottomSpacePx,
+ deviceProfile.taskbarBottomMargin);
+ // Adjust handle view size to accommodate the handle morphing into the bubble bar
+ mStashedHandleView.getLayoutParams().height = barSize + maxTy;
mStashedHandleAlpha.get(0).setValue(0);
- mStashedTaskbarHeight = resources.getDimensionPixelSize(
+ mStashedBubbleBarHeight = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_size);
mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- float stashedHandleRadius = view.getHeight() / 2f;
- outline.setRoundRect(mStashedHandleBounds, stashedHandleRadius);
+ mStashedHandleRadius = view.getHeight() / 2f;
+ outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius);
}
});
@@ -132,28 +146,25 @@
private void updateBounds(BubbleBarLocation bubbleBarLocation) {
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
// handle bar position, we pin it to the edge of the screen.
- final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
+ final int stashedCenterY = mStashedHandleView.getHeight() - mStashedBubbleBarHeight / 2;
+ final int stashedCenterX;
if (bubbleBarLocation.isOnLeft(mStashedHandleView.isLayoutRtl())) {
final int left = mBarViewController.getHorizontalMargin();
- mStashedHandleBounds.set(
- left,
- stashedCenterY - mStashedHandleHeight / 2,
- left + mStashedHandleWidth,
- stashedCenterY + mStashedHandleHeight / 2);
- mStashedHandleView.setPivotX(0);
+ stashedCenterX = left + mStashedHandleWidth / 2;
} else {
final int right =
- mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
- mStashedHandleBounds.set(
- right - mStashedHandleWidth,
- stashedCenterY - mStashedHandleHeight / 2,
- right,
- stashedCenterY + mStashedHandleHeight / 2);
- mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
+ mStashedHandleView.getRight() - mBarViewController.getHorizontalMargin();
+ stashedCenterX = right - mStashedHandleWidth / 2;
}
-
+ mStashedHandleBounds.set(
+ stashedCenterX - mStashedHandleWidth / 2,
+ stashedCenterY - mStashedHandleHeight / 2,
+ stashedCenterX + mStashedHandleWidth / 2,
+ stashedCenterY + mStashedHandleHeight / 2
+ );
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
- mStashedHandleView.setPivotY(mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2f);
+ mStashedHandleView.setPivotX(stashedCenterX);
+ mStashedHandleView.setPivotY(stashedCenterY);
}
public void onDestroy() {
@@ -162,6 +173,13 @@
}
/**
+ * Returns the width of the stashed handle.
+ */
+ public int getStashedWidth() {
+ return mStashedHandleWidth;
+ }
+
+ /**
* Returns the height of the stashed handle.
*/
public int getStashedHeight() {
@@ -169,10 +187,10 @@
}
/**
- * Returns the height when the bubble bar is unstashed (so the height of the bubble bar).
+ * Returns bounds of the stashed handle view
*/
- public int getUnstashedHeight() {
- return mBarSize;
+ public void getBounds(Rect bounds) {
+ bounds.set(mStashedHandleBounds);
}
/**
@@ -242,7 +260,20 @@
* Sets the translation of the stashed handle during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
- mStashedHandleView.setTranslationY(transY);
+ mTranslationForSwipeY = transY;
+ updateTranslationY();
+ }
+
+ /**
+ * Sets the translation of the stashed handle during the spring on stash animation.
+ */
+ public void setTranslationYForStash(float transY) {
+ mTranslationForStashY = transY;
+ updateTranslationY();
+ }
+
+ private void updateTranslationY() {
+ mStashedHandleView.setTranslationY(mTranslationForSwipeY + mTranslationForStashY);
}
/** Returns the translation of the stashed handle. */
@@ -263,18 +294,17 @@
* the size of where the bubble bar icons will be.
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
- Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
+ Rect bubbleBarBounds = getLocalBubbleBarBounds();
- // Account for the full visual height of the bubble bar
- int heightDiff = (mBarSize - bubbleBarBounds.height()) / 2;
- bubbleBarBounds.top -= heightDiff;
- bubbleBarBounds.bottom += heightDiff;
- float stashedHandleRadius = mStashedHandleView.getHeight() / 2f;
+ float bubbleBarRadius = bubbleBarBounds.height() / 2f;
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
- stashedHandleRadius, stashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
+ bubbleBarRadius, mStashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
boolean isReversed = !isStashed;
- boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
+ // We are only changing direction when mWasLastRevealAnimReversed is set at least once
+ boolean changingDirection =
+ mWasLastRevealAnimReversed != null && mWasLastRevealAnimReversed != isReversed;
+
mWasLastRevealAnimReversed = isReversed;
if (changingDirection) {
mStartProgressForNextRevealAnim = 1f - mStartProgressForNextRevealAnim;
@@ -291,6 +321,21 @@
return revealAnim;
}
+ /**
+ * Get bounds for the bubble bar in the space of the handle view
+ */
+ private Rect getLocalBubbleBarBounds() {
+ // Position the bubble bar bounds to the space of handle view
+ Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
+ // Start by moving bubble bar bounds to the bottom of handle view
+ int height = bubbleBarBounds.height();
+ bubbleBarBounds.bottom = mStashedHandleView.getHeight();
+ bubbleBarBounds.top = bubbleBarBounds.bottom - height;
+ // Then apply translation that is applied to the bubble bar
+ bubbleBarBounds.offset(0, (int) mBubbleStashController.getBubbleBarTranslationY());
+ return bubbleBarBounds;
+ }
+
/** Checks that the stash handle is visible and that the motion event is within bounds. */
public boolean isEventOverHandle(MotionEvent ev) {
if (mStashedHandleView.getVisibility() != VISIBLE) {
@@ -298,15 +343,11 @@
}
// the bounds of the handle only include the visible part, so we check that the Y coordinate
- // is anywhere within the stashed taskbar height.
- int top = mActivity.getDeviceProfile().heightPx - mStashedTaskbarHeight;
-
- return (int) ev.getRawY() >= top && containsX((int) ev.getRawX());
- }
-
- /** Checks if the given x coordinate is within the stashed handle bounds. */
- public boolean containsX(int x) {
- return x >= mStashedHandleBounds.left && x <= mStashedHandleBounds.right;
+ // is anywhere within the stashed height of bubble bar (same as taskbar stashed height).
+ final int top = mActivity.getDeviceProfile().heightPx - mStashedBubbleBarHeight;
+ final float x = ev.getRawX();
+ return ev.getRawY() >= top && x >= mStashedHandleBounds.left
+ && x <= mStashedHandleBounds.right;
}
/** Set a bubble bar location */
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index f0f2872..561df5c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
@@ -34,9 +35,9 @@
import com.android.launcher3.R;
import com.android.launcher3.icons.DotRenderer;
-import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.bubbles.BubbleInfo;
+import com.android.wm.shell.shared.animation.Interpolators;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleInfo;
// TODO: (b/276978250) This is will be similar to WMShell's BadgedImageView, it'd be nice to share.
@@ -110,6 +111,10 @@
setFocusable(true);
setClickable(true);
+
+ // We manage the shadow ourselves when creating the bitmap
+ setOutlineAmbientShadowColor(Color.TRANSPARENT);
+ setOutlineSpotShadowColor(Color.TRANSPARENT);
}
private void updateBubbleSizeAndDotRender() {
@@ -152,16 +157,16 @@
applyDragTranslation();
}
+ private void applyDragTranslation() {
+ setTranslationX(mDragTranslationX + mOffsetX);
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
updateBubbleSizeAndDotRender();
}
- private void applyDragTranslation() {
- setTranslationX(mDragTranslationX + mOffsetX);
- }
-
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
@@ -237,7 +242,11 @@
mBubble = bubble;
mIcon = bubble.getIcon();
updateBubbleIcon();
- mAppIcon.setImageBitmap(bubble.getBadge());
+ if (bubble.getInfo().showAppBadge()) {
+ mAppIcon.setImageBitmap(bubble.getBadge());
+ } else {
+ mAppIcon.setVisibility(GONE);
+ }
mDotColor = bubble.getDotColor();
mDotRenderer = new DotRenderer(mBubbleSize, bubble.getDotPath(), DEFAULT_PATH_SIZE);
String contentDesc = bubble.getInfo().getTitle();
@@ -302,8 +311,10 @@
}
void setBadgeScale(float fraction) {
- mAppIcon.setScaleX(fraction);
- mAppIcon.setScaleY(fraction);
+ if (mAppIcon.getVisibility() == VISIBLE) {
+ mAppIcon.setScaleX(fraction);
+ mAppIcon.setScaleY(fraction);
+ }
}
boolean hasUnseenContent() {
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 b745193..6a955d9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -36,6 +36,7 @@
constructor(
private val bubbleBarView: BubbleBarView,
private val bubbleStashController: BubbleStashController,
+ private val onExpanded: Runnable,
private val scheduler: Scheduler = HandlerScheduler(bubbleBarView)
) {
@@ -43,7 +44,13 @@
private val bubbleBarBounceDistanceInPx =
bubbleBarView.resources.getDimensionPixelSize(R.dimen.bubblebar_bounce_distance)
- fun hasAnimatingBubble() = animatingBubble != null
+ 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. */
@@ -157,12 +164,13 @@
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
bubbleBarView.scaleX = 1f
bubbleBarView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
+ bubbleBarView.setBackgroundScaleX(1f)
+ bubbleBarView.setBackgroundScaleY(1f)
bubbleBarView.relativePivotY = 0.5f
// this is the offset between the center of the bubble bar and the center of the stash
@@ -304,8 +312,8 @@
animator.addEndListener { _, _, _, canceled, _, _, _ ->
animatingBubble = null
if (!canceled) bubbleStashController.stashBubbleBarImmediate()
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleBarView.relativePivotY = 1f
+ bubbleBarView.scaleY = 1f
bubbleStashController.updateTaskbarTouchRegion()
}
animator.start()
@@ -330,7 +338,6 @@
Runnable {
animatingBubble = null
bubbleStashController.showBubbleBarImmediate()
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleStashController.updateTaskbarTouchRegion()
}
}
@@ -343,7 +350,6 @@
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
@@ -382,7 +388,6 @@
val hideAnimation = Runnable {
animatingBubble = null
bubbleStashController.showBubbleBarImmediate()
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleStashController.updateTaskbarTouchRegion()
}
animatingBubble =
@@ -398,7 +403,6 @@
*/
private fun buildBubbleBarBounceAnimation() = Runnable {
moveToState(AnimatingBubble.State.ANIMATING_IN)
- bubbleBarView.onAnimatingBubbleStarted()
val ty = bubbleStashController.bubbleBarTranslationY
val springBackAnimation = PhysicsAnimator.getInstance(bubbleBarView)
@@ -406,7 +410,7 @@
springBackAnimation.spring(DynamicAnimation.TRANSLATION_Y, ty)
springBackAnimation.addEndListener { _, _, _, _, _, _, _ ->
if (animatingBubble?.expand == true) {
- bubbleBarView.isExpanded = true
+ expandBubbleBar()
cancelHideAnimation()
} else {
moveToState(AnimatingBubble.State.IN)
@@ -417,7 +421,7 @@
ObjectAnimator.ofFloat(bubbleBarView, View.TRANSLATION_Y, ty - bubbleBarBounceDistanceInPx)
.withDuration(BUBBLE_BAR_BOUNCE_ANIMATION_DURATION_MS)
.withEndAction {
- if (animatingBubble?.expand == true) bubbleBarView.isExpanded = true
+ if (animatingBubble?.expand == true) expandBubbleBar()
springBackAnimation.start()
}
.start()
@@ -429,7 +433,6 @@
bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleBarView.relativePivotY = 1f
animatingBubble = null
}
@@ -440,7 +443,6 @@
scheduler.cancel(hideAnimation)
animatingBubble = null
bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleBarView.relativePivotY = 1f
bubbleStashController.onNewBubbleAnimationInterrupted(
/* isStashed= */ bubbleBarView.alpha == 0f,
@@ -453,7 +455,7 @@
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
+ expandBubbleBar()
cancelHideAnimation()
}
}
@@ -462,7 +464,6 @@
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
animatingBubble = null
- bubbleBarView.onAnimatingBubbleCompleted()
bubbleBarView.relativePivotY = 1f
bubbleStashController.showBubbleBarImmediate()
}
@@ -492,6 +493,11 @@
this.animatingBubble = animatingBubble.copy(state = state)
}
+ private fun expandBubbleBar() {
+ bubbleBarView.isExpanded = true
+ onExpanded.run()
+ }
+
/**
* 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
@@ -513,7 +519,7 @@
}
val expand = animatingBubble?.expand ?: false
if (reachedPeak && expand && !startedExpanding) {
- bubbleBarView.isExpanded = true
+ expandBubbleBar()
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 48eb7de..9721792 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar.bubbles.stashing
+import android.graphics.Rect
import android.view.InsetsController
import android.view.MotionEvent
import android.view.View
@@ -23,8 +24,8 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
import java.io.PrintWriter
/** StashController that defines stashing behaviour for the taskbar modes. */
@@ -146,6 +147,9 @@
/** Returns the translation of the handle. */
fun getHandleTranslationY(): Float?
+ /** Returns bounds of the handle */
+ fun getHandleBounds(bounds: Rect)
+
/**
* Returns bubble bar Y position according to [isBubblesShowingOnHome] and
* [isBubblesShowingOnOverview] values. Default implementation only analyse
@@ -181,8 +185,5 @@
/** How long to translate Y coordinate of the BubbleBar. */
const val BAR_TRANSLATION_DURATION = 300L
-
- /** The scale bubble bar animates to when being stashed. */
- const val STASHED_BAR_SCALE = 0.5f
}
}
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 1b65019..7d6f7ad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -19,6 +19,7 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
+import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
import com.android.launcher3.anim.AnimatedFloat
@@ -30,8 +31,8 @@
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
import com.android.launcher3.util.MultiPropertyFactory
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
class PersistentBubbleStashController(
private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
@@ -116,7 +117,7 @@
bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
// bubble bar has only alpha property, getting it at index 0
bubbleBarAlphaAnimator = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
- bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScale
+ bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScaleY
}
private fun animateAfterUnlock() {
@@ -200,6 +201,10 @@
override fun getHandleTranslationY(): Float? = null
+ override fun getHandleBounds(bounds: Rect) {
+ // no op since does not have a handle view
+ }
+
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 1a4b982..4f0337d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -17,30 +17,37 @@
package com.android.launcher3.taskbar.bubbles.stashing
import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
-import android.content.res.Resources
+import android.content.Context
+import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
import androidx.annotation.VisibleForTesting
+import androidx.core.animation.doOnEnd
+import androidx.core.animation.doOnStart
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.app.animation.Interpolators.LINEAR
import com.android.launcher3.R
import com.android.launcher3.anim.AnimatedFloat
-import com.android.launcher3.taskbar.StashedHandleViewController
+import com.android.launcher3.anim.SpringAnimationBuilder
import com.android.launcher3.taskbar.TaskbarInsetsController
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_DURATION
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_START_DELAY
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_TRANSLATION_DURATION
-import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.STASHED_BAR_SCALE
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
import com.android.launcher3.util.MultiPropertyFactory
-import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
+import kotlin.math.max
class TransientBubbleStashController(
private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
- resources: Resources
+ private val context: Context,
) : BubbleStashController {
private lateinit var bubbleBarViewController: BubbleBarViewController
@@ -50,14 +57,24 @@
// stash view properties
private var bubbleStashedHandleViewController: BubbleStashedHandleViewController? = null
private var stashHandleViewAlpha: MultiPropertyFactory<View>.MultiProperty? = null
+ private var translationYDuringStash = AnimatedFloat { transY ->
+ bubbleStashedHandleViewController?.setTranslationYForStash(transY)
+ bubbleBarViewController.setTranslationYForStash(transY)
+ }
+ private val stashHandleStashVelocity =
+ context.resources.getDimension(R.dimen.bubblebar_stashed_handle_spring_velocity_dp_per_s)
private var stashedHeight: Int = 0
// bubble bar properties
private lateinit var bubbleBarAlpha: MultiPropertyFactory<View>.MultiProperty
+ private lateinit var bubbleBarBubbleAlpha: AnimatedFloat
+ private lateinit var bubbleBarBackgroundAlpha: AnimatedFloat
private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
- private lateinit var bubbleBarScale: AnimatedFloat
- private val mHandleCenterFromScreenBottom =
- resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
+ private lateinit var bubbleBarBubbleTranslationY: AnimatedFloat
+ private lateinit var bubbleBarBackgroundScaleX: AnimatedFloat
+ private lateinit var bubbleBarBackgroundScaleY: AnimatedFloat
+ private val handleCenterFromScreenBottom =
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
private var animator: AnimatorSet? = null
@@ -127,21 +144,22 @@
taskbarInsetsController: TaskbarInsetsController,
bubbleBarViewController: BubbleBarViewController,
bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
- controllersAfterInitAction: ControllersAfterInitAction
+ controllersAfterInitAction: ControllersAfterInitAction,
) {
this.taskbarInsetsController = taskbarInsetsController
this.bubbleBarViewController = bubbleBarViewController
this.bubbleStashedHandleViewController = bubbleStashedHandleViewController
this.controllersAfterInitAction = controllersAfterInitAction
bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
+ bubbleBarBubbleTranslationY = bubbleBarViewController.bubbleOffsetY
// bubble bar has only alpha property, getting it at index 0
bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
- bubbleBarScale = bubbleBarViewController.bubbleBarScale
+ bubbleBarBubbleAlpha = bubbleBarViewController.bubbleBarBubbleAlpha
+ bubbleBarBackgroundAlpha = bubbleBarViewController.bubbleBarBackgroundAlpha
+ bubbleBarBackgroundScaleX = bubbleBarViewController.bubbleBarBackgroundScaleX
+ bubbleBarBackgroundScaleY = bubbleBarViewController.bubbleBarBackgroundScaleY
stashedHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
- stashHandleViewAlpha =
- bubbleStashedHandleViewController
- ?.stashedHandleAlpha
- ?.get(StashedHandleViewController.ALPHA_INDEX_STASHED)
+ stashHandleViewAlpha = bubbleStashedHandleViewController?.stashedHandleAlpha?.get(0)
}
private fun animateAfterUnlock() {
@@ -149,9 +167,12 @@
if (isBubblesShowingOnHome || isBubblesShowingOnOverview) {
isStashed = false
animatorSet.playTogether(
- bubbleBarScale.animateToValue(1f),
+ bubbleBarBackgroundScaleX.animateToValue(1f),
+ bubbleBarBackgroundScaleY.animateToValue(1f),
bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
- bubbleBarAlpha.animateToValue(1f)
+ bubbleBarAlpha.animateToValue(1f),
+ bubbleBarBubbleAlpha.animateToValue(1f),
+ bubbleBarBackgroundAlpha.animateToValue(1f),
)
} else {
isStashed = true
@@ -169,7 +190,10 @@
stashHandleViewAlpha?.value = 0f
this.bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY)
bubbleBarAlpha.setValue(1f)
- bubbleBarScale.updateValue(1f)
+ bubbleBarBubbleAlpha.updateValue(1f)
+ bubbleBarBackgroundAlpha.updateValue(1f)
+ bubbleBarBackgroundScaleX.updateValue(1f)
+ bubbleBarBackgroundScaleY.updateValue(1f)
isStashed = false
onIsStashedChanged()
}
@@ -179,7 +203,11 @@
stashHandleViewAlpha?.value = 1f
this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation())
bubbleBarAlpha.setValue(0f)
- bubbleBarScale.updateValue(STASHED_BAR_SCALE)
+ // Reset bubble and background alpha to 1 and only keep the bubble bar alpha at 0
+ bubbleBarBubbleAlpha.updateValue(1f)
+ bubbleBarBackgroundAlpha.updateValue(1f)
+ bubbleBarBackgroundScaleX.updateValue(getStashScaleX())
+ bubbleBarBackgroundScaleY.updateValue(getStashScaleY())
isStashed = true
onIsStashedChanged()
}
@@ -223,11 +251,11 @@
// the difference between the centers of the handle and the bubble bar is the difference
// between their distance from the bottom of the screen.
val barCenter: Float = bubbleBarViewController.bubbleBarCollapsedHeight / 2f
- return mHandleCenterFromScreenBottom - barCenter
+ return handleCenterFromScreenBottom - barCenter
}
override fun getStashedHandleTranslationForNewBubbleAnimation(): Float {
- return -mHandleCenterFromScreenBottom
+ return -handleCenterFromScreenBottom
}
override fun getStashedHandlePhysicsAnimator(): PhysicsAnimator<View>? {
@@ -244,8 +272,24 @@
override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
+ override fun getHandleBounds(bounds: Rect) {
+ bubbleStashedHandleViewController?.getBounds(bounds)
+ }
+
private fun getStashTranslation(): Float {
- return (bubbleBarViewController.bubbleBarCollapsedHeight - stashedHeight) / 2f
+ return (bubbleBarTranslationY - stashedHeight) / 2f
+ }
+
+ @VisibleForTesting
+ fun getStashScaleX(): Float {
+ val handleWidth = bubbleStashedHandleViewController?.stashedWidth ?: 0
+ return handleWidth / bubbleBarViewController.bubbleBarCollapsedWidth
+ }
+
+ @VisibleForTesting
+ fun getStashScaleY(): Float {
+ val handleHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
+ return handleHeight / bubbleBarViewController.bubbleBarCollapsedHeight
}
/**
@@ -258,61 +302,153 @@
@Suppress("SameParameterValue")
private fun createStashAnimator(isStashed: Boolean, duration: Long): AnimatorSet {
val animatorSet = AnimatorSet()
- val fullLengthAnimatorSet = AnimatorSet()
- // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
- val firstHalfAnimatorSet = AnimatorSet()
- val secondHalfAnimatorSet = AnimatorSet()
- val firstHalfDurationScale: Float
- val secondHalfDurationScale: Float
- val stashHandleAlphaValue: Float
- if (isStashed) {
- firstHalfDurationScale = 0.75f
- secondHalfDurationScale = 0.5f
- stashHandleAlphaValue = 1f
- fullLengthAnimatorSet.play(
- bubbleBarTranslationYAnimator.animateToValue(getStashTranslation())
- )
- firstHalfAnimatorSet.playTogether(
- bubbleBarAlpha.animateToValue(0f),
- bubbleBarScale.animateToValue(STASHED_BAR_SCALE)
- )
- } else {
- firstHalfDurationScale = 0.5f
- secondHalfDurationScale = 0.75f
- stashHandleAlphaValue = 0f
- fullLengthAnimatorSet.playTogether(
- bubbleBarScale.animateToValue(1f),
- bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY)
- )
- secondHalfAnimatorSet.playTogether(bubbleBarAlpha.animateToValue(1f))
- }
- stashHandleViewAlpha?.let {
- secondHalfAnimatorSet.playTogether(it.animateToValue(stashHandleAlphaValue))
- }
- bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.let {
- fullLengthAnimatorSet.play(it)
- }
- fullLengthAnimatorSet.setDuration(duration)
- firstHalfAnimatorSet.setDuration((duration * firstHalfDurationScale).toLong())
- secondHalfAnimatorSet.setDuration((duration * secondHalfDurationScale).toLong())
- secondHalfAnimatorSet.startDelay = (duration * (1 - secondHalfDurationScale)).toLong()
- animatorSet.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet, secondHalfAnimatorSet)
- animatorSet.addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- animator = null
- controllersAfterInitAction.runAfterInit {
- if (isStashed) {
- bubbleBarViewController.isExpanded = false
- }
- taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
- }
- }
+
+ animatorSet.play(
+ createBackgroundAlphaAnimator(isStashed).apply {
+ val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
+ val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
+ this.duration = max(0L, alphaDuration - alphaDelay)
+ this.startDelay = alphaDelay
+ this.interpolator = LINEAR
}
)
+
+ animatorSet.play(
+ bubbleBarBubbleAlpha
+ .animateToValue(getBarAlphaStart(isStashed), getBarAlphaEnd(isStashed))
+ .apply {
+ this.duration = TASKBAR_STASH_ALPHA_DURATION
+ this.startDelay = TASKBAR_STASH_ALPHA_START_DELAY
+ this.interpolator = LINEAR
+ }
+ )
+
+ animatorSet.play(
+ createSpringOnStashAnimator(isStashed).apply {
+ this.duration = duration
+ this.interpolator = LINEAR
+ }
+ )
+
+ animatorSet.play(
+ bubbleBarViewController.createRevealAnimatorForStashChange(isStashed).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
+ // Animate bubble translation to keep reveal animation in the bounds of the bar
+ val bubbleTyStart = if (isStashed) 0f else -bubbleBarTranslationY
+ val bubbleTyEnd = if (isStashed) -bubbleBarTranslationY else 0f
+ animatorSet.play(
+ bubbleBarBubbleTranslationY.animateToValue(bubbleTyStart, bubbleTyEnd).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
+ animatorSet.play(
+ bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
+ val pivotX = if (bubbleBarViewController.isBubbleBarOnLeft) 0f else 1f
+ animatorSet.play(
+ createScaleAnimator(isStashed).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ this.setBubbleBarPivotDuringAnim(pivotX, 1f)
+ }
+ )
+
+ val translationYTarget = if (isStashed) getStashTranslation() else bubbleBarTranslationY
+ animatorSet.play(
+ bubbleBarTranslationYAnimator.animateToValue(translationYTarget).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
+ animatorSet.doOnStart {
+ // Update the start value for bubble view and background alpha when the entire animation
+ // begins.
+ // Alpha animation has a delay, and if we set the initial values at the start of the
+ // alpha animation, it will cause flickers.
+ bubbleBarBubbleAlpha.updateValue(getBarAlphaStart(isStashed))
+ bubbleBarBackgroundAlpha.updateValue(getBarAlphaStart(isStashed))
+ // We animate alpha for background and bubble views separately. Make sure the container
+ // is always visible.
+ bubbleBarAlpha.value = 1f
+ }
+ animatorSet.doOnEnd {
+ animator = null
+ controllersAfterInitAction.runAfterInit {
+ if (isStashed) {
+ bubbleBarAlpha.value = 0f
+ // reset bubble view alpha
+ bubbleBarBubbleAlpha.updateValue(1f)
+ bubbleBarBackgroundAlpha.updateValue(1f)
+ // reset stash translation
+ translationYDuringStash.updateValue(0f)
+ bubbleBarBubbleTranslationY.updateValue(0f)
+ bubbleBarViewController.isExpanded = false
+ }
+ taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+ }
return animatorSet
}
+ private fun createBackgroundAlphaAnimator(isStashed: Boolean): AnimatorSet {
+ return AnimatorSet().apply {
+ play(
+ bubbleBarBackgroundAlpha.animateToValue(
+ getBarAlphaStart(isStashed),
+ getBarAlphaEnd(isStashed),
+ )
+ )
+ play(stashHandleViewAlpha?.animateToValue(getHandleAlphaEnd(isStashed)))
+ }
+ }
+
+ private fun getBarAlphaStart(isStashed: Boolean): Float {
+ return if (isStashed) 1f else 0f
+ }
+
+ private fun getBarAlphaEnd(isStashed: Boolean): Float {
+ return if (isStashed) 0f else 1f
+ }
+
+ private fun getHandleAlphaEnd(isStashed: Boolean): Float {
+ return if (isStashed) 1f else 0f
+ }
+
+ private fun createSpringOnStashAnimator(isStashed: Boolean): Animator {
+ if (!isStashed) {
+ // Animate the stash translation back to 0
+ return translationYDuringStash.animateToValue(0f)
+ }
+ // Apply a spring to the handle
+ return SpringAnimationBuilder(context)
+ .setStartValue(translationYDuringStash.value)
+ .setEndValue(0f)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .setStartVelocity(stashHandleStashVelocity)
+ .build(translationYDuringStash, AnimatedFloat.VALUE)
+ }
+
+ private fun createScaleAnimator(isStashed: Boolean): AnimatorSet {
+ val scaleXTarget = if (isStashed) getStashScaleX() else 1f
+ val scaleYTarget = if (isStashed) getStashScaleY() else 1f
+ return AnimatorSet().apply {
+ play(bubbleBarBackgroundScaleX.animateToValue(scaleXTarget))
+ play(bubbleBarBackgroundScaleY.animateToValue(scaleYTarget))
+ }
+ }
+
private fun onIsStashedChanged() {
controllersAfterInitAction.runAfterInit {
taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
@@ -363,13 +499,23 @@
}
private fun Animator.updateTouchRegionOnAnimationEnd(): Animator {
- this.addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- onIsStashedChanged()
- }
+ doOnEnd { onIsStashedChanged() }
+ return this
+ }
+
+ private fun Animator.setBubbleBarPivotDuringAnim(pivotX: Float, pivotY: Float): Animator {
+ var initialPivotX = Float.NaN
+ var initialPivotY = Float.NaN
+ doOnStart {
+ initialPivotX = bubbleBarViewController.bubbleBarRelativePivotX
+ initialPivotY = bubbleBarViewController.bubbleBarRelativePivotY
+ bubbleBarViewController.setBubbleBarRelativePivot(pivotX, pivotY)
+ }
+ doOnEnd {
+ if (!initialPivotX.isNaN() && !initialPivotY.isNaN()) {
+ bubbleBarViewController.setBubbleBarRelativePivot(initialPivotX, initialPivotY)
}
- )
+ }
return this
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index 7d2d36d..726800c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -18,18 +18,27 @@
import android.annotation.SuppressLint
import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color.TRANSPARENT
import android.util.AttributeSet
import android.view.LayoutInflater
-import android.widget.LinearLayout
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewConfiguration
import androidx.annotation.DimenRes
import androidx.annotation.DrawableRes
import androidx.core.view.setPadding
import com.android.launcher3.R
import com.android.launcher3.Utilities.dpToPx
-import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR
+import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarViewCallbacks
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.IconButtonView
+import com.android.quickstep.DeviceConfigWrapper
+import com.android.quickstep.util.AssistStateManager
/** Taskbar all apps button container for customizable taskbar. */
class TaskbarAllAppsButtonContainer
@@ -38,19 +47,21 @@
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
-) : LinearLayout(context, attrs), TaskbarContainer {
+) : IconButtonView(context, attrs), TaskbarContainer {
- private val allAppsButton: IconButtonView =
- LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, this, false)
- as IconButtonView
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+ private var allAppsTouchTriggered = false
+ private var allAppsTouchRunnable: Runnable? = null
+ private var allAppsButtonTouchDelayMs: Long = ViewConfiguration.getLongPressTimeout().toLong()
+ private lateinit var taskbarViewCallbacks: TaskbarViewCallbacks
override val spaceNeeded: Int
get() {
- return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+ return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
}
init {
+ LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, null, false)
setUpIcon()
}
@@ -58,24 +69,39 @@
private fun setUpIcon() {
val drawable =
resources.getDrawable(
- getAllAppsButton(activityContext.taskbarFeatureEvaluator!!.isTransient)
+ getAllAppsButton(activityContext.taskbarFeatureEvaluator.isTransient)
)
- val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+ backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
+ setIconDrawable(drawable)
+ setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+ setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
+ }
- allAppsButton.setIconDrawable(drawable)
- allAppsButton.setPadding(padding)
- allAppsButton.setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
-
- // TODO(b/356465292) : add click listeners in future cl
- addView(allAppsButton)
+ @SuppressLint("ClickableViewAccessibility")
+ fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
+ taskbarViewCallbacks = callbacks
+ setOnClickListener(this::onAllAppsButtonClick)
+ setOnLongClickListener(this::onAllAppsButtonLongClick)
+ setOnTouchListener(this::onAllAppsButtonTouch)
+ isHapticFeedbackEnabled = taskbarViewCallbacks.isAllAppsButtonHapticFeedbackEnabled()
+ allAppsTouchRunnable = Runnable {
+ taskbarViewCallbacks.triggerAllAppsButtonLongClick()
+ allAppsTouchTriggered = true
+ }
+ val assistStateManager = AssistStateManager.INSTANCE[mContext]
+ if (
+ DeviceConfigWrapper.get().customLpaaThresholds &&
+ assistStateManager.lpnhDurationMillis.isPresent
+ ) {
+ allAppsButtonTouchDelayMs = assistStateManager.lpnhDurationMillis.get()
+ }
}
@DrawableRes
private fun getAllAppsButton(isTransientTaskbar: Boolean): Int {
val shouldSelectTransientIcon =
- isTransientTaskbar ||
- (FeatureFlags.enableTaskbarPinning() && !activityContext.isThreeButtonNav)
- return if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+ isTransientTaskbar || (enableTaskbarPinning() && !activityContext.isThreeButtonNav)
+ return if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_search_button
else R.drawable.ic_taskbar_all_apps_search_button
} else {
@@ -88,10 +114,43 @@
fun getAllAppsButtonTranslationXOffset(isTransientTaskbar: Boolean): Int {
return if (isTransientTaskbar) {
R.dimen.transient_taskbar_all_apps_button_translation_x_offset
- } else if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+ } else if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
R.dimen.taskbar_all_apps_search_button_translation_x_offset
} else {
R.dimen.taskbar_all_apps_button_translation_x_offset
}
}
+
+ private fun onAllAppsButtonTouch(view: View, ev: MotionEvent): Boolean {
+ when (ev.action) {
+ MotionEvent.ACTION_DOWN -> {
+ allAppsTouchTriggered = false
+ MAIN_EXECUTOR.handler.postDelayed(allAppsTouchRunnable!!, allAppsButtonTouchDelayMs)
+ }
+ MotionEvent.ACTION_UP,
+ MotionEvent.ACTION_CANCEL -> cancelAllAppsButtonTouch()
+ }
+ return false
+ }
+
+ private fun cancelAllAppsButtonTouch() {
+ MAIN_EXECUTOR.handler.removeCallbacks(allAppsTouchRunnable!!)
+ // ACTION_UP is first triggered, then click listener / long-click listener is triggered on
+ // the next frame, so we need to post twice and delay the reset.
+ this.post { this.post { allAppsTouchTriggered = false } }
+ }
+
+ private fun onAllAppsButtonClick(view: View) {
+ if (!allAppsTouchTriggered) {
+ taskbarViewCallbacks.triggerAllAppsButtonClick(view)
+ }
+ }
+
+ // Handle long click from Switch Access and Voice Access
+ private fun onAllAppsButtonLongClick(view: View): Boolean {
+ if (!MAIN_EXECUTOR.handler.hasCallbacks(allAppsTouchRunnable!!) && !allAppsTouchTriggered) {
+ taskbarViewCallbacks.triggerAllAppsButtonLongClick()
+ }
+ return true
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
index 26e71f7..1fb835a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -18,13 +18,15 @@
import android.annotation.SuppressLint
import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color.TRANSPARENT
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.taskbar.TaskbarViewCallbacks
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.IconButtonView
@@ -35,31 +37,30 @@
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
+) : IconButtonView(context, attrs), TaskbarContainer {
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
override val spaceNeeded: Int
get() {
- return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+ return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
}
init {
+ LayoutInflater.from(context).inflate(R.layout.taskbar_divider, null, false)
setUpIcon()
}
@SuppressLint("UseCompatLoadingForDrawables")
fun setUpIcon() {
+ backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
- val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+ setIconDrawable(drawable)
+ setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+ }
- taskbarDivider.setIconDrawable(drawable)
- taskbarDivider.setPadding(padding)
-
- // TODO(b/356465292):: add click listeners in future cl
- addView(taskbarDivider)
+ @SuppressLint("ClickableViewAccessibility")
+ fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
+ setOnLongClickListener(callbacks.taskbarDividerLongClickListener)
+ setOnTouchListener(callbacks.taskbarDividerRightClickListener)
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt
index c83ac50..7739a0e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt
@@ -26,23 +26,6 @@
private constructor(
private val taskbarActivityContext: TaskbarActivityContext,
) {
-
- companion object {
- @Volatile private lateinit var taskbarFeatureEvaluator: TaskbarFeatureEvaluator
-
- @JvmStatic
- fun getInstance(
- taskbarActivityContext: TaskbarActivityContext,
- ): TaskbarFeatureEvaluator {
- synchronized(this) {
- if (!::taskbarFeatureEvaluator.isInitialized) {
- taskbarFeatureEvaluator = TaskbarFeatureEvaluator(taskbarActivityContext)
- }
- return taskbarFeatureEvaluator
- }
- }
- }
-
val hasAllApps = true
val hasAppIcons = true
val hasBubbles = false
@@ -59,4 +42,24 @@
val isLandscape: Boolean
get() = taskbarActivityContext.deviceProfile.isLandscape
+
+ fun onDestroy() {
+ taskbarFeatureEvaluator = null
+ }
+
+ companion object {
+ @Volatile private var taskbarFeatureEvaluator: TaskbarFeatureEvaluator? = null
+
+ @JvmStatic
+ fun getInstance(
+ taskbarActivityContext: TaskbarActivityContext,
+ ): TaskbarFeatureEvaluator {
+ synchronized(this) {
+ if (taskbarFeatureEvaluator == null) {
+ taskbarFeatureEvaluator = TaskbarFeatureEvaluator(taskbarActivityContext)
+ }
+ return taskbarFeatureEvaluator!!
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
index 887eb01..e55cb1f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
@@ -19,10 +19,11 @@
/** Taskbar Icon Specs */
object TaskbarIconSpecs {
- val iconSize40dp = TaskbarIconSize(40)
- val iconSize44dp = TaskbarIconSize(44)
- val iconSize48dp = TaskbarIconSize(48)
- val iconSize52dp = TaskbarIconSize(52)
+ // Mapping of visual icon size to icon specs value http://b/235886078
+ val iconSize40dp = TaskbarIconSize(44)
+ val iconSize44dp = TaskbarIconSize(48)
+ val iconSize48dp = TaskbarIconSize(52)
+ val iconSize52dp = TaskbarIconSize(57)
val transientTaskbarIconSizes = arrayOf(iconSize44dp, iconSize48dp, iconSize52dp)
@@ -36,6 +37,8 @@
val minimumTaskbarIconTouchSize = TaskbarIconSize(48)
+ val transientOrPinnedTaskbarIconPaddingSize = iconSize52dp
+
val transientTaskbarIconSizeByGridSize =
mapOf(
TransientTaskbarIconSizeKey(6, 5, false) to iconSize52dp,
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
index 761b47e..822ca64 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
@@ -25,14 +25,17 @@
numRows: Int = taskbarActivityContext.deviceProfile.inv.numRows,
numColumns: Int = taskbarActivityContext.deviceProfile.inv.numColumns,
) {
- var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numRows, numColumns)
+ var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numColumns, numRows)
// TODO(b/341146605) : initialize it to taskbar container in later cl.
private var taskbarContainer: List<TaskbarContainer> = emptyList()
val taskbarIconPadding: Int =
- if (TaskbarIconSpecs.minimumTaskbarIconTouchSize.size > taskbarIconSize.size) {
- (TaskbarIconSpecs.minimumTaskbarIconTouchSize.size - taskbarIconSize.size) / 2
+ if (
+ TaskbarIconSpecs.transientOrPinnedTaskbarIconPaddingSize.size > taskbarIconSize.size &&
+ !taskbarFeatureEvaluator.hasNavButtons
+ ) {
+ (TaskbarIconSpecs.iconSize52dp.size - taskbarIconSize.size) / 2
} else {
0
}
@@ -44,10 +47,10 @@
TaskbarIconSpecs.defaultPersistentIconMargin
}
- fun getIconSizeByGrid(row: Int, column: Int): TaskbarIconSize {
+ fun getIconSizeByGrid(columns: Int, rows: Int): TaskbarIconSize {
return if (taskbarFeatureEvaluator.isTransient) {
TaskbarIconSpecs.transientTaskbarIconSizeByGridSize.getOrDefault(
- TransientTaskbarIconSizeKey(row, column, taskbarFeatureEvaluator.isLandscape),
+ TransientTaskbarIconSizeKey(columns, rows, taskbarFeatureEvaluator.isLandscape),
TaskbarIconSpecs.defaultTransientIconSize,
)
} else {
@@ -102,6 +105,6 @@
data class TaskbarIconSize(val size: Int)
-data class TransientTaskbarIconSizeKey(val row: Int, val column: Int, val isLandscape: Boolean)
+data class TransientTaskbarIconSizeKey(val columns: Int, val rows: Int, val isLandscape: Boolean)
data class TaskbarIconMarginSize(val size: Int)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 110ca16..4590efe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.Keyframe;
@@ -39,6 +40,7 @@
import android.os.Process;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.Property;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -71,12 +73,27 @@
*/
public class PredictedAppIcon extends DoubleShadowBubbleTextView {
+ private static final float RING_SCALE_START_VALUE = 0.75f;
private static final int RING_SHADOW_COLOR = 0x99000000;
private static final float RING_EFFECT_RATIO = 0.095f;
private static final long ICON_CHANGE_ANIM_DURATION = 360;
private static final long ICON_CHANGE_ANIM_STAGGER = 50;
+ private static final Property<PredictedAppIcon, Float> RING_SCALE_PROPERTY =
+ new Property<>(Float.TYPE, "ringScale") {
+ @Override
+ public Float get(PredictedAppIcon icon) {
+ return icon.mRingScale;
+ }
+
+ @Override
+ public void set(PredictedAppIcon icon, Float value) {
+ icon.mRingScale = value;
+ icon.invalidate();
+ }
+ };
+
boolean mIsDrawingDot = false;
private final DeviceProfile mDeviceProfile;
private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -96,6 +113,11 @@
private Animator mSlotMachineAnim;
private float mSlotMachineIconTranslationY;
+ // Used to animate the "ring" around predicted icons
+ private float mRingScale = 1f;
+ private boolean mForceHideRing = false;
+ private Animator mRingScaleAnim;
+
private static final FloatProperty<PredictedAppIcon> SLOT_MACHINE_TRANSLATION_Y =
new FloatProperty<PredictedAppIcon>("slotMachineTranslationY") {
@Override
@@ -356,17 +378,52 @@
}
}
+ @Override
+ public void setForceHideRing(boolean forceHideRing) {
+ if (mForceHideRing == forceHideRing) {
+ return;
+ }
+ mForceHideRing = forceHideRing;
+
+ if (forceHideRing) {
+ invalidate();
+ } else {
+ animateRingScale(RING_SCALE_START_VALUE, 1);
+ }
+ }
+
+ private void cancelRingScaleAnim() {
+ if (mRingScaleAnim != null) {
+ mRingScaleAnim.cancel();
+ }
+ }
+
+ private void animateRingScale(float... ringScale) {
+ cancelRingScaleAnim();
+ mRingScaleAnim = ObjectAnimator.ofFloat(this, RING_SCALE_PROPERTY, ringScale);
+ mRingScaleAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mRingScaleAnim = null;
+ }
+ });
+ mRingScaleAnim.start();
+ }
+
private void drawEffect(Canvas canvas) {
- // Don't draw ring effect if item is about to be dragged.
- if (mDrawForDrag) {
+ // Don't draw ring effect if item is about to be dragged or if the icon is not visible.
+ if (mDrawForDrag || !mIsIconVisible || mForceHideRing) {
return;
}
mIconRingPaint.setColor(RING_SHADOW_COLOR);
mIconRingPaint.setMaskFilter(mShadowFilter);
+ int count = canvas.save();
+ canvas.scale(mRingScale, mRingScale, canvas.getWidth() / 2f, canvas.getHeight() / 2f);
canvas.drawPath(mRingPath, mIconRingPaint);
mIconRingPaint.setColor(mPlateColor);
mIconRingPaint.setMaskFilter(null);
canvas.drawPath(mRingPath, mIconRingPaint);
+ canvas.restoreToCount(count);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 039c0a0..93cbdc7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -22,7 +22,6 @@
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.Intent;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
@@ -66,13 +65,7 @@
}
Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view);
ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager()
- .getActivityLaunchOptions(hostView);
- Object itemInfo = hostView.getTag();
- IBinder launchCookie = null;
- if (itemInfo instanceof ItemInfo) {
- launchCookie = mLauncher.getLaunchCookie((ItemInfo) itemInfo);
- activityOptions.options.setLaunchCookie(launchCookie);
- }
+ .getActivityLaunchOptions(hostView, (ItemInfo) hostView.getTag());
if (Utilities.ATLEAST_S && !pendingIntent.isActivity()) {
// In the event this pending intent eventually launches an activity, i.e. a trampoline,
// use the Quickstep transition animation.
@@ -81,7 +74,7 @@
.registerRemoteAnimationForNextActivityStart(
pendingIntent.getCreatorPackage(),
activityOptions.options.getRemoteAnimationAdapter(),
- launchCookie);
+ activityOptions.options.getLaunchCookie());
} catch (RemoteException e) {
// Do nothing.
}
@@ -92,7 +85,7 @@
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
options = Pair.create(options.first, activityOptions.options);
if (pendingIntent.isActivity()) {
- logAppLaunch(itemInfo);
+ logAppLaunch(hostView.getTag());
}
return RemoteViews.startPendingIntent(hostView, pendingIntent, options);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index b2cc369..1f5cd3a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -22,7 +22,6 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -42,9 +41,9 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
-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;
@@ -64,9 +63,9 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.QUICK_SWITCH_FROM_HOME_FALLBACK;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -75,6 +74,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;
@@ -82,7 +82,6 @@
import android.media.permission.SafeCloseable;
import android.os.Build;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.SystemProperties;
import android.os.Trace;
@@ -215,7 +214,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 =
@@ -227,7 +227,6 @@
private FixedContainerItems mAllAppsPredictions;
private HotseatPredictionController mHotseatPredictionController;
private DepthController mDepthController;
- private @Nullable DesktopVisibilityController mDesktopVisibilityController;
private QuickstepTransitionManager mAppTransitionManager;
private OverviewActionsView<?> mActionsView;
@@ -301,8 +300,6 @@
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
mDepthController = new DepthController(this);
if (DesktopModeStatus.canEnterDesktopMode(this)) {
- mDesktopVisibilityController = new DesktopVisibilityController(this);
- mDesktopVisibilityController.registerSystemUiListener();
mSplitSelectStateController.initSplitFromDesktopController(this,
overviewComponentObserver);
}
@@ -466,6 +463,9 @@
if (Flags.enablePrivateSpace()) {
shortcuts.add(UNINSTALL_APP);
}
+ if (com.android.wm.shell.Flags.enableBubbleAnything()) {
+ shortcuts.add(BUBBLE_SHORTCUT);
+ }
return shortcuts.stream();
}
@@ -493,10 +493,8 @@
boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0;
if (started) {
DeviceProfile profile = getDeviceProfile();
- boolean willUserBeActive =
- (getActivityFlags() & ACTIVITY_STATE_USER_WILL_BE_ACTIVE) != 0;
boolean visible = (state == NORMAL || state == OVERVIEW)
- && (willUserBeActive || isUserActive())
+ && isUserActive()
&& !profile.isVerticalBarLayout()
&& !mIsOverlayVisible;
SystemUiProxy.INSTANCE.get(this)
@@ -553,10 +551,6 @@
mLauncherUnfoldAnimationController.onDestroy();
}
- if (mDesktopVisibilityController != null) {
- mDesktopVisibilityController.unregisterSystemUiListener();
- }
-
if (mSplitSelectStateController != null) {
mSplitSelectStateController.onDestroy();
}
@@ -607,7 +601,7 @@
.append(" is missing."),
QUICK_SWITCH_FROM_HOME_FALLBACK);
}
- taskToLaunch.launchTask(success -> {
+ taskToLaunch.launchWithoutAnimation(success -> {
if (!success) {
getStateManager().goToState(OVERVIEW);
} else {
@@ -690,9 +684,7 @@
// Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
// work, we must opt-in BEFORE registering back dispatcher. So we need to call
// setEnableOnBackInvokedCallback() before super.onCreate()
- if (Utilities.ATLEAST_U && enablePredictiveBackGesture()) {
- getApplicationInfo().setEnableOnBackInvokedCallback(true);
- }
+ getApplicationInfo().setEnableOnBackInvokedCallback(true);
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mPendingSplitSelectInfo = ObjectWrapper.unwrap(
@@ -700,9 +692,7 @@
}
addMultiWindowModeChangedListener(mDepthController);
initUnfoldTransitionProgressProvider();
- if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
- mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow());
- }
+ mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow());
getWindow().addPrivateFlags(PRIVATE_FLAG_OPTIMIZE_MEASURE);
QuickstepOnboardingPrefs.setup(this);
View.setTraceLayoutSteps(TRACE_LAYOUTS);
@@ -723,7 +713,7 @@
// Check if there is already an instance of this app running, if so, initiate the split
// using that.
mSplitSelectStateController.findLastActiveTasksAndRunCallback(
- Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
+ Collections.singletonList(splitSelectSource.getItemInfo().getComponentKey()),
false /* findExactPairMatch */,
foundTasks -> {
@Nullable Task foundTask = foundTasks[0];
@@ -750,7 +740,7 @@
Rect tempRect = new Rect();
mSplitSelectStateController.setInitialTaskSelect(source.intent,
- source.position.stagePosition, source.itemInfo, source.splitEvent,
+ source.position.stagePosition, source.getItemInfo(), source.splitEvent,
source.alreadyRunningTaskId);
RecentsView recentsView = getOverviewPanel();
@@ -768,6 +758,8 @@
floatingTaskView.setOnClickListener(view ->
mSplitSelectStateController.getSplitAnimationController().
playAnimPlaceholderToFullscreen(this, view, Optional.empty()));
+ floatingTaskView.setContentDescription(source.getItemInfo().contentDescription);
+
mSplitSelectStateController.setFirstFloatingTaskView(floatingTaskView);
anim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -902,8 +894,7 @@
// event won't go through ViewRootImpl#InputStage#onProcess.
// So when receive back key, try to do the same check thing in
// ViewRootImpl#NativePreImeInputStage#onProcess
- if (!Utilities.ATLEAST_U || !enablePredictiveBackGesture()
- || event.getKeyCode() != KeyEvent.KEYCODE_BACK
+ if (event.getKeyCode() != KeyEvent.KEYCODE_BACK
|| event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) {
return false;
}
@@ -914,10 +905,6 @@
@Override
protected void registerBackDispatcher() {
- if (!enablePredictiveBackGesture()) {
- super.registerBackDispatcher();
- return;
- }
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
new OnBackAnimationCallback() {
@@ -1015,10 +1002,11 @@
@Override
public void setResumed() {
+ DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
if (!WALLPAPER_ACTIVITY.isEnabled(this)
- && mDesktopVisibilityController != null
- && mDesktopVisibilityController.areDesktopTasksVisible()
- && !mDesktopVisibilityController.isRecentsGestureInProgress()) {
+ && desktopVisibilityController != null
+ && desktopVisibilityController.areDesktopTasksVisible()
+ && !desktopVisibilityController.isRecentsGestureInProgress()) {
// Return early to skip setting activity to appear as resumed
// TODO: b/333533253 - Remove after flag rollout
return;
@@ -1158,8 +1146,9 @@
}
@Nullable
+ @Override
public DesktopVisibilityController getDesktopVisibilityController() {
- return mDesktopVisibilityController;
+ return mTISBindHelper.getDesktopVisibilityController();
}
@Nullable
@@ -1194,7 +1183,8 @@
@Override
public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
- ActivityOptionsWrapper activityOptions = mAppTransitionManager.getActivityLaunchOptions(v);
+ ActivityOptionsWrapper activityOptions = mAppTransitionManager.getActivityLaunchOptions(
+ v, item != null ? item : (ItemInfo) v.getTag());
if (mLastTouchUpTime > 0) {
activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER,
mLastTouchUpTime);
@@ -1234,47 +1224,6 @@
mSplitWithKeyboardShortcutController.enterStageSplit(leftOrTop);
}
- /**
- * Return a new launch cookie for the activity launch if supported.
- *
- * @param info the item info for the launch
- */
- public IBinder getLaunchCookie(ItemInfo info) {
- if (info == null) {
- return null;
- }
- switch (info.container) {
- case Favorites.CONTAINER_DESKTOP:
- case Favorites.CONTAINER_HOTSEAT:
- case Favorites.CONTAINER_PRIVATESPACE:
- // Fall through and continue it's on the workspace (we don't support swiping back
- // to other containers like all apps or the hotseat predictions (which can change)
- break;
- default:
- if (info.container >= 0) {
- // Also allow swiping to folders
- break;
- }
- // Reset any existing launch cookies associated with the cookie
- return ObjectWrapper.wrap(NO_MATCHING_ID);
- }
- switch (info.itemType) {
- case Favorites.ITEM_TYPE_APPLICATION:
- case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- case Favorites.ITEM_TYPE_APPWIDGET:
- // Fall through and continue if it's an app, shortcut, or widget
- break;
- default:
- // Reset any existing launch cookies associated with the cookie
- return ObjectWrapper.wrap(NO_MATCHING_ID);
- }
- return ObjectWrapper.wrap(new Integer(info.id));
- }
-
- public void setHintUserWillBeActive() {
- addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
- }
-
@Override
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
super.onDisplayInfoChanged(context, info, flags);
@@ -1353,8 +1302,9 @@
@Override
public boolean areDesktopTasksVisible() {
- if (mDesktopVisibilityController != null) {
- return mDesktopVisibilityController.areDesktopTasksVisible();
+ DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
+ if (desktopVisibilityController != null) {
+ return desktopVisibilityController.areDesktopTasksVisible();
}
return false;
}
@@ -1382,10 +1332,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 +1350,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 +1398,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/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index fa80dc2..030a7ac 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -26,7 +26,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.util.BaseDepthController;
@@ -202,17 +201,6 @@
}
@Override
- public float[] getOverviewScaleAndOffset(Launcher launcher) {
- if (!FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()) {
- return super.getOverviewScaleAndOffset(launcher);
- }
- // This handles the case of returning to the previous app from Overview -> All Apps gesture.
- // This is the start scale/offset of overview that will be used for that transition.
- // TODO (b/283336332): Translate in Y direction (ideally with overview resistance).
- return new float[] {0.5f /* scale */, NO_OFFSET};
- }
-
- @Override
public int getWorkspaceScrimColor(Launcher launcher) {
return launcher.getDeviceProfile().isTablet
? launcher.getResources().getColor(R.color.widgets_picker_scrim)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 2625646..18d717f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import android.content.Context;
import android.graphics.Color;
@@ -51,9 +50,11 @@
return super.getVerticalProgress(launcher);
}
RecentsView recentsView = launcher.getOverviewPanel();
- int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher,
+ int transitionLength = LayoutUtils.getShelfTrackingDistance(
+ launcher,
launcher.getDeviceProfile(),
- recentsView.getPagedOrientationHandler());
+ recentsView.getPagedOrientationHandler(),
+ recentsView.getSizeStrategy());
AllAppsTransitionController controller = launcher.getAllAppsController();
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
@@ -107,8 +108,7 @@
@Override
public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
- if (ENABLE_SHELL_TRANSITIONS) return false;
- return super.isTaskbarAlignedWithHotseat(launcher);
+ return false;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 6822f1b..b165cdd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -209,7 +209,7 @@
TaskView taskView = recentsView.getRunningTaskView();
if (taskView != null) {
if (recentsView.isTaskViewFullyVisible(taskView)) {
- taskView.launchTasks();
+ taskView.launchWithAnimation();
} else {
recentsView.snapToPage(recentsView.indexOfChild(taskView));
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index d1aa472..ff726e6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -42,7 +42,6 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -221,11 +220,6 @@
mCancelSplitRunnable.accept(animatorSet, duration);
animatorSet.start();
}
- if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() &&
- ((mFromState == NORMAL && mToState == ALL_APPS)
- || (mFromState == ALL_APPS && mToState == NORMAL)) && isFling) {
- mVibratorWrapper.vibrateForDragBump();
- }
}
private void onMotionPauseDetected() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 0da7b2d..9164405 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -129,7 +129,10 @@
mRecentsView = mLauncher.getOverviewPanel();
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
mYRange = LayoutUtils.getShelfTrackingDistance(
- mLauncher, mLauncher.getDeviceProfile(), mRecentsView.getPagedOrientationHandler());
+ mLauncher,
+ mLauncher.getDeviceProfile(),
+ mRecentsView.getPagedOrientationHandler(),
+ mRecentsView.getSizeStrategy());
mMaxYProgress = mLauncher.getDeviceProfile().heightPx / mYRange;
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index b5914a1..b562838 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -29,7 +29,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.AllAppsSwipeController;
@@ -93,9 +92,7 @@
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
if (fromState == ALL_APPS && !isDragTowardPositive) {
- return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
- ? mLauncher.getStateManager().getLastState()
- : NORMAL;
+ return NORMAL;
} else if (fromState == NORMAL && shouldOpenAllApps(isDragTowardPositive)) {
return ALL_APPS;
}
@@ -145,8 +142,11 @@
.createPlaybackController();
mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
RecentsView recentsView = mLauncher.getOverviewPanel();
- totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher,
- mLauncher.getDeviceProfile(), recentsView.getPagedOrientationHandler());
+ totalShift = LayoutUtils.getShelfTrackingDistance(
+ mLauncher,
+ mLauncher.getDeviceProfile(),
+ recentsView.getPagedOrientationHandler(),
+ recentsView.getSizeStrategy());
} else {
mCurrentAnimation = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mToState, config);
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..202276e 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;
@@ -181,7 +181,7 @@
// - The task is snapped
mAllowGoingDown = i == mRecentsView.getCurrentPage()
&& DisplayController.getNavigationMode(mContainer).hasGestures
- && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isFocusedTask())
+ && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isLargeTile())
&& mRecentsView.isTaskInExpectedScrollPosition(i);
directionsToDetectScroll = mAllowGoingDown ? DIRECTION_BOTH : upDirection;
@@ -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();
@@ -312,7 +310,7 @@
// Set mOverrideVelocity to control task dismiss velocity in onDragEnd
int velocityDimenId = R.dimen.default_task_dismiss_drag_velocity;
if (mRecentsView.showAsGrid()) {
- if (mTaskBeingDragged.isFocusedTask()) {
+ if (mTaskBeingDragged.isLargeTile()) {
velocityDimenId =
R.dimen.default_task_dismiss_drag_velocity_grid_focus_task;
} else {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 4dc04e7..240d6ad 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -45,7 +45,6 @@
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
-import static com.android.quickstep.GestureState.GestureEndTarget.ALL_APPS;
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
@@ -53,6 +52,7 @@
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_CANCELED;
+import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
@@ -96,6 +96,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.Cuj;
import com.android.internal.util.LatencyTracker;
@@ -105,6 +106,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 +142,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;
@@ -148,10 +151,10 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
-import com.android.wm.shell.startingsurface.SplashScreenExitAnimationUtils;
+import com.android.wm.shell.shared.startingsurface.SplashScreenExitAnimationUtils;
import kotlin.Unit;
@@ -167,10 +170,12 @@
/**
* Handles the navigation gestures when Launcher is the default home activity.
*/
-public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
- Q extends RecentsView, S extends BaseState<S>>
- extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener,
- RecentsAnimationCallbacks.RecentsAnimationListener {
+public abstract class AbsSwipeUpHandler<
+ RECENTS_CONTAINER extends Context & RecentsViewContainer,
+ RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
+ STATE extends BaseState<STATE>>
+ extends SwipeUpAnimationLogic
+ implements OnApplyWindowInsetsListener, RecentsAnimationCallbacks.RecentsAnimationListener {
private static final String TAG = "AbsSwipeUpHandler";
private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
@@ -178,7 +183,7 @@
// Fraction of the scroll and transform animation in which the current task fades out
private static final float KQS_TASK_FADE_ANIMATION_FRACTION = 0.4f;
- protected final BaseContainerInterface<S, T> mContainerInterface;
+ protected final BaseContainerInterface<STATE, RECENTS_CONTAINER> mContainerInterface;
protected final InputConsumerProxy mInputConsumerProxy;
protected final ActivityInitListener mActivityInitListener;
// Callbacks to be made once the recents animation starts
@@ -187,10 +192,9 @@
// Null if the recents animation hasn't started yet or has been canceled or finished.
protected @Nullable RecentsAnimationController mRecentsAnimationController;
- protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController;
protected RecentsAnimationTargets mRecentsAnimationTargets;
- protected @Nullable T mContainer;
- protected @Nullable Q mRecentsView;
+ protected @Nullable RECENTS_CONTAINER mContainer;
+ protected @Nullable RECENTS_VIEW mRecentsView;
protected Runnable mGestureEndCallback;
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
@@ -259,8 +263,6 @@
getNextStateFlag("STATE_CURRENT_TASK_FINISHED");
private static final int STATE_FINISH_WITH_NO_END =
getNextStateFlag("STATE_FINISH_WITH_NO_END");
- private static final int STATE_SETTLED_ON_ALL_APPS =
- getNextStateFlag("STATE_SETTLED_ON_ALL_APPS");
private static final int LAUNCHER_UI_STATES =
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED |
@@ -314,7 +316,6 @@
private boolean mGestureStarted;
private boolean mLogDirectionUpOrLeft = true;
private boolean mIsLikelyToStartNewTask;
- private boolean mIsInAllAppsRegion;
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
@@ -451,9 +452,6 @@
this::finishCurrentTransitionToHome);
mStateCallback.runOnceAtState(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED,
this::reset);
- mStateCallback.runOnceAtState(STATE_SETTLED_ON_ALL_APPS | STATE_SCREENSHOT_CAPTURED
- | STATE_GESTURE_COMPLETED,
- this::finishCurrentTransitionToAllApps);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
| STATE_LAUNCHER_DRAWN | STATE_SCALED_CONTROLLER_RECENTS
@@ -466,6 +464,8 @@
mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED
| STATE_RECENTS_SCROLLING_FINISHED,
this::onSettledOnEndTarget);
+ mGestureState.runOnceAtState(STATE_END_TARGET_SET | STATE_RECENTS_ANIMATION_STARTED,
+ this::onCalculateEndTarget);
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
@@ -481,11 +481,11 @@
return false;
}
- T createdContainer = (T) mContainerInterface.getCreatedContainer();
+ RECENTS_CONTAINER createdContainer = mContainerInterface.getCreatedContainer();
if (createdContainer != null) {
initTransitionEndpoints(createdContainer.getDeviceProfile());
}
- final T container = (T) mContainerInterface.getCreatedContainer();
+ final RECENTS_CONTAINER container = mContainerInterface.getCreatedContainer();
if (mContainer == container) {
return true;
}
@@ -532,14 +532,7 @@
HashMap<Integer, ThumbnailData> snapshots =
mGestureState.consumeRecentsAnimationCanceledSnapshot();
if (snapshots != null) {
- mRecentsView.switchToScreenshot(snapshots, () -> {
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.cleanupScreenshot();
- } else if (mDeferredCleanupRecentsAnimationController != null) {
- mDeferredCleanupRecentsAnimationController.cleanupScreenshot();
- mDeferredCleanupRecentsAnimationController = null;
- }
- });
+ mRecentsView.switchToScreenshot(snapshots, () -> {});
mRecentsView.onRecentsAnimationComplete();
}
});
@@ -559,7 +552,7 @@
}
private void onLauncherStart() {
- final T container = (T) mContainerInterface.getCreatedContainer();
+ final RECENTS_CONTAINER container = mContainerInterface.getCreatedContainer();
if (container == null || mContainer != container) {
return;
}
@@ -716,9 +709,7 @@
maybeUpdateRecentsAttachedState(true/* animate */, true/* moveRunningTask */);
Optional.ofNullable(mContainerInterface.getTaskbarController())
.ifPresent(TaskbarUIController::startTranslationSpring);
- if (!mIsInAllAppsRegion) {
- performHapticFeedback();
- }
+ performHapticFeedback();
}
@Override
@@ -729,11 +720,18 @@
}
private void maybeUpdateRecentsAttachedState() {
- maybeUpdateRecentsAttachedState(true /* animate */);
+ maybeUpdateRecentsAttachedState(/* animate= */ true);
}
protected void maybeUpdateRecentsAttachedState(boolean animate) {
- maybeUpdateRecentsAttachedState(animate, false /* moveRunningTask */);
+ maybeUpdateRecentsAttachedState(animate, /* moveRunningTask= */ false);
+ }
+
+ protected void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
+ maybeUpdateRecentsAttachedState(
+ animate,
+ moveRunningTask,
+ mRecentsView != null && mRecentsView.shouldUpdateRunningTaskAlpha());
}
/**
@@ -744,8 +742,10 @@
* Note this method has no effect unless the navigation mode is NO_BUTTON.
* @param animate whether to animate when attaching RecentsView
* @param moveRunningTask whether to move running task to front when attaching
+ * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
*/
- private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
+ private void maybeUpdateRecentsAttachedState(
+ boolean animate, boolean moveRunningTask, boolean updateRunningTaskAlpha) {
if ((!mDeviceState.isFullyGesturalNavMode() && !mGestureState.isTrackpadGesture())
|| mRecentsView == null) {
return;
@@ -757,9 +757,7 @@
.findTask(mGestureState.getTopRunningTaskId())
: null;
final boolean recentsAttachedToAppWindow;
- if (mIsInAllAppsRegion) {
- recentsAttachedToAppWindow = false;
- } else if (mGestureState.getEndTarget() != null) {
+ if (mGestureState.getEndTarget() != null) {
recentsAttachedToAppWindow = mGestureState.getEndTarget().recentsAttachedToAppWindow;
} else if (mContinuingLastGesture
&& mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) {
@@ -776,7 +774,8 @@
// TaskView jumping to new position as we move the tasks.
mRecentsView.moveRunningTaskToFront();
}
- mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
+ mAnimationFactory.setRecentsAttachedToAppWindow(
+ recentsAttachedToAppWindow, animate, updateRunningTaskAlpha);
// Reapply window transform throughout the attach animation, as the animation affects how
// much the window is bound by overscroll (vs moving freely).
@@ -815,31 +814,6 @@
}
}
- /**
- * Update whether user is currently dragging in a region that will trigger all apps.
- */
- private void setIsInAllAppsRegion(boolean isInAllAppsRegion) {
- if (mIsInAllAppsRegion == isInAllAppsRegion
- || !mContainerInterface.allowAllAppsFromOverview()) {
- return;
- }
- mIsInAllAppsRegion = isInAllAppsRegion;
-
- // Newly entering or exiting the zone - do haptic and animate recent tasks.
- VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
- maybeUpdateRecentsAttachedState(true);
-
- if (mContainer != null) {
- mContainer.getAppsView().getSearchUiManager()
- .prepareToFocusEditText(mIsInAllAppsRegion);
- }
-
- // Draw active task below Launcher so that All Apps can appear over it.
- runActionOnRemoteHandles(remoteTargetHandle ->
- remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(isInAllAppsRegion));
- }
-
-
private void buildAnimationController() {
if (!canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
@@ -899,8 +873,6 @@
@UiThread
@Override
public void onCurrentShiftUpdated() {
- float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f;
- setIsInAllAppsRegion(mCurrentShift.value >= threshold);
updateSysUiFlags(mCurrentShift.value);
applyScrollAndTransform();
@@ -934,7 +906,6 @@
// We will handle the sysui flags based on the centermost task view.
mRecentsAnimationController.setUseLauncherSystemBarFlags(swipeUpThresholdPassed
|| (quickswitchThresholdPassed && centermostTaskFlags != 0));
- mRecentsAnimationController.setSplitScreenMinimized(mContext, swipeUpThresholdPassed);
// Provide a hint to WM the direction that we will be settling in case the animation
// needs to be canceled
mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed);
@@ -1008,9 +979,6 @@
/* event= */ "cancelRecentsAnimation",
/* gestureEvent= */ CANCEL_RECENTS_ANIMATION);
mActivityInitListener.unregister("AbsSwipeUpHandler.onRecentsAnimationCanceled");
- // Cache the recents animation controller so we can defer its cleanup to after having
- // properly cleaned up the screenshot without accidentally using it.
- mDeferredCleanupRecentsAnimationController = mRecentsAnimationController;
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
// Defer clearing the controller and the targets until after we've updated the state
mRecentsAnimationController = null;
@@ -1082,7 +1050,7 @@
*/
@UiThread
private void notifyGestureStarted() {
- final T curActivity = mContainer;
+ final RECENTS_CONTAINER curActivity = mContainer;
if (curActivity != null) {
// Once the gesture starts, we can no longer transition home through the button, so
// reset the force override of the activity visibility
@@ -1150,7 +1118,25 @@
}
}
- private void onSettledOnEndTarget() {
+ /**
+ * Called if the end target has been set and the recents animation is started.
+ */
+ @VisibleForTesting
+ protected void onCalculateEndTarget() {
+ final GestureEndTarget endTarget = mGestureState.getEndTarget();
+
+ switch (endTarget) {
+ case HOME:
+ // Early detach the nav bar if endTarget is determined as HOME
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.detachNavigationBarFromApp(true);
+ }
+ break;
+ }
+ }
+
+ @VisibleForTesting
+ protected void onSettledOnEndTarget() {
// Fast-finish the attaching animation if it's still running.
maybeUpdateRecentsAttachedState(false);
final GestureEndTarget endTarget = mGestureState.getEndTarget();
@@ -1168,9 +1154,6 @@
}
switch (endTarget) {
- case ALL_APPS:
- mStateCallback.setState(STATE_SETTLED_ON_ALL_APPS | STATE_CAPTURE_SCREENSHOT);
- break;
case HOME:
mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
// Notify the SysUI to use fade-in animation when entering PiP
@@ -1289,9 +1272,6 @@
final boolean willGoToNewTask =
isScrollingToNewTask() && Math.abs(velocity.x) > Math.abs(endVelocity);
final boolean isSwipeUp = endVelocity < 0;
- if (mIsInAllAppsRegion) {
- return isSwipeUp ? ALL_APPS : LAST_TASK;
- }
if (!isSwipeUp) {
final boolean isCenteredOnNewTask = mRecentsView != null
&& mRecentsView.getDestinationPage() != mRecentsView.getRunningTaskIndex();
@@ -1307,9 +1287,7 @@
// Fully gestural mode.
final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_speed);
- if (mIsInAllAppsRegion) {
- return ALL_APPS;
- } else if (isScrollingToNewTask && isFlingX) {
+ if (isScrollingToNewTask && isFlingX) {
// Flinging towards new task takes precedence over mIsMotionPaused (which only
// checks y-velocity).
return NEW_TASK;
@@ -1364,8 +1342,7 @@
.setUserIsNotGoingHome(endTarget != GestureState.GestureEndTarget.HOME);
}
- float endShift = endTarget == ALL_APPS ? mDragLengthFactor
- : endTarget.isLauncher ? 1 : 0;
+ float endShift = endTarget.isLauncher ? 1 : 0;
final float startShift;
if (!isFling) {
long expectedDuration = Math.abs(Math.round((endShift - currentShift)
@@ -1386,7 +1363,7 @@
}
}
Interpolator interpolator;
- S state = mContainerInterface.stateFromGestureEndTarget(endTarget);
+ STATE state = mContainerInterface.stateFromGestureEndTarget(endTarget);
if (isKeyboardTaskFocusPending()) {
interpolator = EMPHASIZED;
} else if (state.displayOverviewTasksAsGrid(mDp)) {
@@ -1404,10 +1381,8 @@
duration = mContainer != null && mContainer.getDeviceProfile().isTaskbarPresent
? StaggeredWorkspaceAnim.DURATION_TASKBAR_MS
: StaggeredWorkspaceAnim.DURATION_MS;
- // Early detach the nav bar once the endTarget is determined as HOME
- 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();
@@ -1432,6 +1407,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()) {
@@ -1736,8 +1713,7 @@
private int calculateWindowRotation(RemoteAnimationTarget runningTaskTarget,
RecentsOrientedState orientationState) {
- if (runningTaskTarget.rotationChange != 0
- && TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ if (runningTaskTarget.rotationChange != 0) {
return Math.abs(runningTaskTarget.rotationChange) == ROTATION_90
? ROTATION_270 : ROTATION_90;
} else {
@@ -1993,12 +1969,6 @@
reset();
}
- @UiThread
- private void finishCurrentTransitionToAllApps() {
- finishCurrentTransitionToHome();
- reset();
- }
-
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
if (mContainer != null) {
@@ -2140,7 +2110,6 @@
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.
@@ -2336,7 +2305,7 @@
ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
}
ActiveGestureLog.INSTANCE.addLog(nextTaskLog);
- nextTask.launchTask(success -> {
+ nextTask.launchWithoutAnimation(true, success -> {
resultCallback.accept(success);
if (success) {
if (hasTaskPreviouslyAppeared) {
@@ -2349,7 +2318,7 @@
}
}
return Unit.INSTANCE;
- }, true /* freezeTaskList */);
+ } /* freezeTaskList */);
} else {
mContainerInterface.onLaunchTaskFailed();
Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show();
@@ -2468,7 +2437,7 @@
}
private void animateSplashScreenExit(
- @NonNull T activity,
+ @NonNull RECENTS_CONTAINER activity,
@NonNull RemoteAnimationTarget[] appearedTaskTargets,
@NonNull RemoteAnimationTarget[] animatingTargets) {
ViewGroup splashView = activity.getDragLayer();
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 293944d..8703843 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -21,11 +21,13 @@
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_ATTACHED_ALPHA_ANIM;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.Animator;
@@ -187,8 +189,10 @@
* @param attached Whether to show RecentsView alongside the app window. If false, recents
* will be hidden by some property we can animate, e.g. alpha.
* @param animate Whether to animate recents to/from its new attached state.
+ * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
*/
- default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
+ default void setRecentsAttachedToAppWindow(
+ boolean attached, boolean animate, boolean updateRunningTaskAlpha) { }
default boolean isRecentsAttachedToAppWindow() {
return false;
@@ -253,12 +257,14 @@
// (because we set the animation as the current state animation), so we reapply the
// attached state here as well to ensure recents is shown/hidden appropriately.
if (DisplayController.getNavigationMode(mActivity) == NavigationMode.NO_BUTTON) {
- setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
+ setRecentsAttachedToAppWindow(
+ mIsAttachedToWindow, false, recentsView.shouldUpdateRunningTaskAlpha());
}
}
@Override
- public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
+ public void setRecentsAttachedToAppWindow(
+ boolean attached, boolean animate, boolean updateRunningTaskAlpha) {
if (mIsAttachedToWindow == attached && animate) {
return;
}
@@ -266,6 +272,10 @@
.cancelStateElementAnimation(INDEX_RECENTS_FADE_ANIM);
mActivity.getStateManager()
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
+ if (updateRunningTaskAlpha) {
+ mActivity.getStateManager()
+ .cancelStateElementAnimation(INDEX_RECENTS_ATTACHED_ALPHA_ANIM);
+ }
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.addListener(new AnimatorListenerAdapter() {
@@ -280,19 +290,28 @@
long animationDuration = animate ? RECENTS_ATTACH_DURATION : 0;
Animator fadeAnim = mActivity.getStateManager()
- .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
+ .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1f : 0f);
fadeAnim.setInterpolator(attached ? INSTANT : ACCELERATE_2);
fadeAnim.setDuration(animationDuration);
animatorSet.play(fadeAnim);
float fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(
mActivity.getOverviewPanel());
- float toTranslation = attached ? 0 : 1;
-
+ float toTranslation = attached ? 0f : 1f;
Animator translationAnimator = mActivity.getStateManager().createStateElementAnimation(
INDEX_RECENTS_TRANSLATE_X_ANIM, fromTranslation, toTranslation);
translationAnimator.setDuration(animationDuration);
animatorSet.play(translationAnimator);
+
+ if (updateRunningTaskAlpha) {
+ float fromAlpha = RUNNING_TASK_ATTACH_ALPHA.get(mActivity.getOverviewPanel());
+ float toAlpha = attached ? 1f : 0f;
+ Animator runningTaskAttachAlphaAnimator = mActivity.getStateManager()
+ .createStateElementAnimation(
+ INDEX_RECENTS_ATTACHED_ALPHA_ANIM, fromAlpha, toAlpha);
+ runningTaskAttachAlphaAnimator.setDuration(animationDuration);
+ animatorSet.play(runningTaskAttachAlphaAnimator);
+ }
animatorSet.start();
}
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 3a8c141..bf3a662 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -68,17 +68,12 @@
public abstract void onAssistantVisibilityChanged(float assistantVisibility);
- public abstract boolean allowMinimizeSplitScreen();
-
public abstract boolean isResumed();
public abstract boolean isStarted();
public abstract boolean deferStartingActivity(RecentsAnimationDeviceState deviceState,
MotionEvent ev);
- /** @return whether to allow going to All Apps from Overview. */
- public abstract boolean allowAllAppsFromOverview();
-
/**
* Returns the color of the scrim behind overview when at rest in this state.
* Return {@link Color#TRANSPARENT} for no scrim.
@@ -133,7 +128,9 @@
@Nullable
public DesktopVisibilityController getDesktopVisibilityController() {
- return null;
+ CONTAINER_TYPE container = getCreatedContainer();
+
+ return container == null ? null : container.getDesktopVisibilityController();
}
/**
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index 358f644..94f4920 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -24,8 +24,8 @@
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskContainer
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
class DesktopSystemShortcut(
@@ -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/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
index 904ed69..f610014 100644
--- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
+++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
@@ -52,7 +52,11 @@
)
val lpnhTimeoutMs =
- propReader.get("LPNH_TIMEOUT_MS", 450, "Controls lpnh timeout in milliseconds")
+ propReader.get(
+ "LPNH_TIMEOUT_MS",
+ DEFAULT_LPNH_TIMEOUT_MS,
+ "Controls lpnh timeout in milliseconds"
+ )
val lpnhSlopPercentage =
propReader.get("LPNH_SLOP_PERCENTAGE", 100, "Controls touch slop percentage for lpnh")
@@ -138,13 +142,6 @@
"Controls extra dp on the nav bar sides to trigger LPNH. Can be negative for a smaller touch region."
)
- val allAppsOverviewThreshold =
- propReader.get(
- "ALL_APPS_OVERVIEW_THRESHOLD",
- 180,
- "Threshold to open All Apps from Overview"
- )
-
/** Dump config values. */
fun dump(prefix: String, writer: PrintWriter) {
writer.println("$prefix DeviceConfigWrapper:")
@@ -165,12 +162,13 @@
writer.println("$prefix\tenableLpnhDeepPress=$enableLpnhDeepPress")
writer.println("$prefix\tlpnhHapticHintDelay=$lpnhHapticHintDelay")
writer.println("$prefix\tlpnhExtraTouchWidthDp=$lpnhExtraTouchWidthDp")
- writer.println("$prefix\tallAppsOverviewThreshold=$allAppsOverviewThreshold")
}
companion object {
@JvmStatic val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
@JvmStatic fun get() = configHelper.config
+
+ const val DEFAULT_LPNH_TIMEOUT_MS = 450
}
}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 89fbf4a..df83eb2 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -133,17 +133,6 @@
}
@Override
- public boolean allowMinimizeSplitScreen() {
- // TODO: Remove this once b/77875376 is fixed
- return false;
- }
-
- @Override
- public boolean allowAllAppsFromOverview() {
- return false;
- }
-
- @Override
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
// In non-gesture mode, user might be clicking on the home button which would directly
// start the home activity instead of going through recents. In that case, defer starting
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 81c9d4a..9cc463a 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -179,7 +179,6 @@
private RemoteAnimationTarget[] mLastAppearedTaskTargets;
private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>();
private int[] mLastStartedTaskId = new int[]{INVALID_TASK_ID, INVALID_TASK_ID};
- private RecentsAnimationController mRecentsAnimationController;
private HashMap<Integer, ThumbnailData> mRecentsAnimationCanceledSnapshots;
/** The time when the swipe up gesture is triggered. */
@@ -470,7 +469,6 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
- mRecentsAnimationController = controller;
mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED);
}
@@ -480,10 +478,6 @@
mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED);
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
if (mRecentsAnimationCanceledSnapshots != null) {
- // Clean up the screenshot to finalize the recents animation cancel
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.cleanupScreenshot();
- }
mRecentsAnimationCanceledSnapshots = null;
}
}
@@ -522,7 +516,7 @@
HashMap<Integer, ThumbnailData> consumeRecentsAnimationCanceledSnapshot() {
if (mRecentsAnimationCanceledSnapshots != null) {
HashMap<Integer, ThumbnailData> data =
- new HashMap<Integer, ThumbnailData>(mRecentsAnimationCanceledSnapshots);
+ new HashMap<>(mRecentsAnimationCanceledSnapshots);
mRecentsAnimationCanceledSnapshots = null;
return data;
}
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index f898e2f..0185737 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -40,6 +40,7 @@
int TYPE_STATUS_BAR = 1 << 13;
int TYPE_CURSOR_HOVER = 1 << 14;
int TYPE_NAV_HANDLE_LONG_PRESS = 1 << 15;
+ int TYPE_BUBBLE_BAR = 1 << 16;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -58,6 +59,7 @@
"TYPE_STATUS_BAR", // 13
"TYPE_CURSOR_HOVER", // 14
"TYPE_NAV_HANDLE_LONG_PRESS", // 15
+ "TYPE_BUBBLE_BAR", // 16
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index b564fa7..85312e4 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -18,7 +18,6 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.FLOATING_SEARCH_BAR;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -40,9 +39,7 @@
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -79,7 +76,7 @@
&& DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
} else {
- return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler);
+ return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler, this);
}
}
@@ -169,16 +166,6 @@
@Nullable
@Override
- public DesktopVisibilityController getDesktopVisibilityController() {
- QuickstepLauncher launcher = getCreatedContainer();
- if (launcher == null) {
- return null;
- }
- return launcher.getDesktopVisibilityController();
- }
-
- @Nullable
- @Override
public LauncherTaskbarUIController getTaskbarController() {
QuickstepLauncher launcher = getCreatedContainer();
if (launcher == null) {
@@ -271,18 +258,6 @@
}
@Override
- public boolean allowMinimizeSplitScreen() {
- return true;
- }
-
- @Override
- public boolean allowAllAppsFromOverview() {
- return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
- // If floating search bar would not show in overview, don't allow all apps gesture.
- && OVERVIEW.areElementsVisible(getCreatedContainer(), FLOATING_SEARCH_BAR);
- }
-
- @Override
public boolean isInLiveTileMode() {
QuickstepLauncher launcher = getCreatedContainer();
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index b720382..1124aac 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -27,7 +27,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.ComponentCallbacks;
import android.content.res.Configuration;
@@ -38,7 +37,6 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
import android.view.Choreographer;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -63,7 +61,7 @@
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.BackAnimState;
import com.android.systemui.shared.system.QuickStepContract;
import java.lang.ref.WeakReference;
@@ -109,8 +107,6 @@
private RemoteAnimationTarget mLauncherTarget;
private View mLauncherTargetView;
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
- private boolean mSpringAnimationInProgress = false;
- private boolean mAnimatorSetInProgress = false;
private float mBackProgress = 0;
private boolean mBackInProgress = false;
private OnBackInvokedCallbackStub mBackCallback;
@@ -341,7 +337,9 @@
mTransaction
.setColor(mScrimLayer, colorComponents)
.setAlpha(mScrimLayer, mScrimAlpha)
- .show(mScrimLayer);
+ .show(mScrimLayer)
+ // Ensure the scrim layer occludes opening task & wallpaper
+ .setLayer(mScrimLayer, 1000);
}
void removeScrimLayer() {
@@ -446,15 +444,15 @@
mQuickstepTransitionManager.transferRectToTargetCoordinate(
mBackTarget, mCurrentRect, true, resolveRectF);
- Pair<RectFSpringAnim, AnimatorSet> pair =
+ BackAnimState backAnim =
mQuickstepTransitionManager.createWallpaperOpenAnimations(
new RemoteAnimationTarget[]{mBackTarget},
new RemoteAnimationTarget[0],
- false /* fromUnlock */,
+ new RemoteAnimationTarget[0],
resolveRectF,
cornerRadius,
mBackInProgress /* fromPredictiveBack */);
- startTransitionAnimations(pair.first, pair.second);
+ startTransitionAnimations(backAnim);
mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
customizeStatusBarAppearance(true);
}
@@ -469,8 +467,6 @@
mCurrentRect.setEmpty();
mStartRect.setEmpty();
mInitialTouchPos.set(0, 0);
- mAnimatorSetInProgress = false;
- mSpringAnimationInProgress = false;
setLauncherTargetViewVisible(true);
mLauncherTargetView = null;
// We don't call customizeStatusBarAppearance here to prevent the status bar update with
@@ -493,27 +489,8 @@
}
}
- private void startTransitionAnimations(RectFSpringAnim springAnim, AnimatorSet anim) {
- mAnimatorSetInProgress = anim != null;
- mSpringAnimationInProgress = springAnim != null;
- if (springAnim != null) {
- springAnim.addAnimatorListener(
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mSpringAnimationInProgress = false;
- tryFinishBackAnimation();
- }
- }
- );
- }
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimatorSetInProgress = false;
- tryFinishBackAnimation();
- }
- });
+ private void startTransitionAnimations(BackAnimState backAnim) {
+ backAnim.addOnAnimCompleteCallback(this::finishAnimation);
if (mScrimLayer == null) {
// Scrim hasn't been attached yet. Let's attach it.
addScrimLayer();
@@ -533,7 +510,7 @@
}
});
mScrimAlphaAnimator.setDuration(SCRIM_FADE_DURATION).start();
- anim.start();
+ backAnim.start();
}
private void loadResources() {
@@ -566,12 +543,6 @@
mScrimAlpha = 0;
}
- private void tryFinishBackAnimation() {
- if (!mSpringAnimationInProgress && !mAnimatorSetInProgress) {
- finishAnimation();
- }
- }
-
private void customizeStatusBarAppearance(boolean overridingStatusBarFlags) {
if (mOverridingStatusBarFlags == overridingStatusBarFlags) {
return;
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index e17cdcd..d2dcd7b 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.Utilities.mapBoundToRange;
-import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
@@ -42,7 +41,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ObjectWrapper;
+import com.android.launcher3.util.StableViewInfo;
import com.android.launcher3.views.ClipIconView;
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
@@ -62,8 +61,8 @@
/**
* Temporary class to allow easier refactoring
*/
-public class LauncherSwipeHandlerV2 extends
- AbsSwipeUpHandler<QuickstepLauncher, RecentsView, LauncherState> {
+public class LauncherSwipeHandlerV2 extends AbsSwipeUpHandler<
+ QuickstepLauncher, RecentsView<QuickstepLauncher, LauncherState>, LauncherState> {
public LauncherSwipeHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
@@ -107,9 +106,6 @@
|| !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
mContainer.getRootView().setForceHideBackArrow(true);
- if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- mContainer.setHintUserWillBeActive();
- }
if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
return new LauncherHomeAnimationFactory() {
@@ -304,18 +300,7 @@
return null;
}
- // Find the associated item info for the launch cookie (if available), note that predicted
- // apps actually have an id of -1, so use another default id here
- int launchCookieItemId = NO_MATCHING_ID;
- for (IBinder cookie : launchCookies) {
- Integer itemId = ObjectWrapper.unwrap(cookie);
- if (itemId != null) {
- launchCookieItemId = itemId;
- break;
- }
- }
-
- return mContainer.getFirstMatchForAppClose(launchCookieItemId,
+ return mContainer.getFirstMatchForAppClose(StableViewInfo.fromLaunchCookies(launchCookies),
sourceTaskView.getFirstTask().key.getComponent().getPackageName(),
UserHandle.of(sourceTaskView.getFirstTask().key.userId),
false /* supportsAllAppsState */);
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 84f6b55..a03c0f8 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -37,6 +37,7 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.window.CachedDisplayInfo;
+import com.android.systemui.shared.Flags;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -242,7 +243,8 @@
int rotation = display.rotation;
int touchHeight = mNavBarGesturalHeight;
OrientationRectF orientationRectF = new OrientationRectF(0, 0, size.x, size.y, rotation);
- if (mMode == NavigationMode.NO_BUTTON) {
+ if (mMode == NavigationMode.NO_BUTTON
+ || (mMode == NavigationMode.THREE_BUTTONS && Flags.threeButtonCornerSwipe())) {
orientationRectF.top = orientationRectF.bottom - touchHeight;
updateAssistantRegions(orientationRectF);
} else {
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
deleted file mode 100644
index 8f533a3..0000000
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static com.android.launcher3.PagedView.INVALID_PAGE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Intent;
-import android.graphics.PointF;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.BinderThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-
-import com.android.internal.jank.Cuj;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.taskbar.TaskbarUIController;
-import com.android.launcher3.util.RunnableList;
-import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
-import com.android.quickstep.util.ActiveGestureLog;
-import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * Helper class to handle various atomic commands for switching between Overview.
- */
-public class OverviewCommandHelper {
- private static final String TAG = "OverviewCommandHelper";
-
- public static final int TYPE_SHOW = 1;
- public static final int TYPE_KEYBOARD_INPUT = 2;
- public static final int TYPE_HIDE = 3;
- public static final int TYPE_TOGGLE = 4;
- public static final int TYPE_HOME = 5;
-
- /**
- * Use case for needing a queue is double tapping recents button in 3 button nav.
- * Size of 2 should be enough. We'll toss in one more because we're kind hearted.
- */
- private final static int MAX_QUEUE_SIZE = 3;
-
- private static final String TRANSITION_NAME = "Transition:toOverview";
-
- private final TouchInteractionService mService;
- private final OverviewComponentObserver mOverviewComponentObserver;
- private final TaskAnimationManager mTaskAnimationManager;
- private final ArrayList<CommandInfo> mPendingCommands = new ArrayList<>();
-
- /**
- * Index of the TaskView that should be focused when launching Overview. Persisted so that we
- * do not lose the focus across multiple calls of
- * {@link OverviewCommandHelper#executeCommand(CommandInfo)} for the same command
- */
- private int mKeyboardTaskFocusIndex = -1;
-
- /**
- * Whether we should incoming toggle commands while a previous toggle command is still ongoing.
- * This serves as a rate-limiter to prevent overlapping animations that can clobber each other
- * and prevent clean-up callbacks from running. This thus prevents a recurring set of bugs with
- * janky recents animations and unresponsive home and overview buttons.
- */
- private boolean mWaitForToggleCommandComplete = false;
-
- public OverviewCommandHelper(TouchInteractionService service,
- OverviewComponentObserver observer,
- TaskAnimationManager taskAnimationManager) {
- mService = service;
- mOverviewComponentObserver = observer;
- mTaskAnimationManager = taskAnimationManager;
- }
-
- /**
- * Called when the command finishes execution.
- */
- private void scheduleNextTask(CommandInfo command) {
- if (mPendingCommands.isEmpty()) {
- Log.d(TAG, "no pending commands to schedule");
- return;
- }
- if (mPendingCommands.get(0) != command) {
- Log.d(TAG, "next task not scheduled."
- + " mPendingCommands[0] type is " + mPendingCommands.get(0)
- + " - command type is: " + command);
- return;
- }
- Log.d(TAG, "scheduleNextTask called: " + command);
- mPendingCommands.remove(0);
- executeNext();
- }
-
- /**
- * Executes the next command from the queue. If the command finishes immediately (returns true),
- * it continues to execute the next command, until the queue is empty of a command defer's its
- * completion (returns false).
- */
- @UiThread
- private void executeNext() {
- if (mPendingCommands.isEmpty()) {
- Log.d(TAG, "executeNext - mPendingCommands is empty");
- return;
- }
- CommandInfo cmd = mPendingCommands.get(0);
-
- boolean result = executeCommand(cmd);
- Log.d(TAG, "executeNext cmd type: " + cmd + ", result: " + result);
- if (result) {
- scheduleNextTask(cmd);
- }
- }
-
- @UiThread
- private void addCommand(CommandInfo cmd) {
- boolean wasEmpty = mPendingCommands.isEmpty();
- mPendingCommands.add(cmd);
- if (wasEmpty) {
- executeNext();
- }
- }
-
- /**
- * Adds a command to be executed next, after all pending tasks are completed.
- * Max commands that can be queued is {@link #MAX_QUEUE_SIZE}.
- * Requests after reaching that limit will be silently dropped.
- */
- @BinderThread
- public void addCommand(int type) {
- if (mPendingCommands.size() >= MAX_QUEUE_SIZE) {
- Log.d(TAG, "the pending command queue is full (" + mPendingCommands.size() + "). "
- + "command not added: " + type);
- return;
- }
- Log.d(TAG, "adding command type: " + type);
- CommandInfo cmd = new CommandInfo(type);
- MAIN_EXECUTOR.execute(() -> addCommand(cmd));
- }
-
- @UiThread
- public void clearPendingCommands() {
- Log.d(TAG, "clearing pending commands - size: " + mPendingCommands.size());
- mPendingCommands.clear();
- }
-
- @UiThread
- public boolean canStartHomeSafely() {
- return mPendingCommands.isEmpty() || mPendingCommands.get(0).type == TYPE_HOME;
- }
-
- @Nullable
- private TaskView getNextTask(RecentsView view) {
- final TaskView runningTaskView = view.getRunningTaskView();
-
- if (runningTaskView == null) {
- return view.getTaskViewAt(0);
- } else {
- final TaskView nextTask = view.getNextTaskView();
- return nextTask != null ? nextTask : runningTaskView;
- }
- }
-
- private boolean launchTask(RecentsView recents, @Nullable TaskView taskView, CommandInfo cmd) {
- RunnableList callbackList = null;
- if (taskView != null) {
- mWaitForToggleCommandComplete = true;
- taskView.setEndQuickSwitchCuj(true);
- callbackList = taskView.launchTasks();
- }
-
- if (callbackList != null) {
- callbackList.add(() -> {
- Log.d(TAG, "launching task callback: " + cmd);
- scheduleNextTask(cmd);
- mWaitForToggleCommandComplete = false;
- });
- Log.d(TAG, "launching task - waiting for callback: " + cmd);
- return false;
- } else {
- recents.startHome();
- mWaitForToggleCommandComplete = false;
- return true;
- }
- }
-
- /**
- * Executes the task and returns true if next task can be executed. If false, then the next
- * task is deferred until {@link #scheduleNextTask} is called
- */
- private <T extends StatefulActivity<?> & RecentsViewContainer> boolean executeCommand(
- CommandInfo cmd) {
- if (mWaitForToggleCommandComplete && cmd.type == TYPE_TOGGLE) {
- Log.d(TAG, "executeCommand: " + cmd
- + " - waiting for toggle command complete");
- return true;
- }
- BaseActivityInterface<?, T> activityInterface =
- mOverviewComponentObserver.getActivityInterface();
-
- RecentsView<?, ?> visibleRecentsView = activityInterface.getVisibleRecentsView();
- RecentsView<?, ?> createdRecentsView;
-
- Log.d(TAG, "executeCommand: " + cmd
- + " - visibleRecentsView: " + visibleRecentsView);
- if (visibleRecentsView == null) {
- T activity = activityInterface.getCreatedContainer();
- createdRecentsView = activity == null ? null : activity.getOverviewPanel();
- DeviceProfile dp = activity == null ? null : activity.getDeviceProfile();
- TaskbarUIController uiController = activityInterface.getTaskbarController();
- boolean allowQuickSwitch = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
- && uiController != null
- && dp != null
- && (dp.isTablet || dp.isTwoPanels);
-
- switch (cmd.type) {
- case TYPE_HIDE:
- if (!allowQuickSwitch) {
- return true;
- }
- mKeyboardTaskFocusIndex = uiController.launchFocusedTask();
- if (mKeyboardTaskFocusIndex == -1) {
- return true;
- }
- break;
- case TYPE_KEYBOARD_INPUT:
- if (allowQuickSwitch) {
- uiController.openQuickSwitchView();
- return true;
- } else {
- mKeyboardTaskFocusIndex = 0;
- break;
- }
- case TYPE_HOME:
- ActiveGestureLog.INSTANCE.addLog(
- "OverviewCommandHelper.executeCommand(TYPE_HOME)");
- // Although IActivityTaskManager$Stub$Proxy.startActivity is a slow binder call,
- // we should still call it on main thread because launcher is waiting for
- // ActivityTaskManager to resume it. Also calling startActivity() on bg thread
- // could potentially delay resuming launcher. See b/348668521 for more details.
- mService.startActivity(mOverviewComponentObserver.getHomeIntent());
- return true;
- case TYPE_SHOW:
- // When Recents is not currently visible, the command's type is TYPE_SHOW
- // when overview is triggered via the keyboard overview button or Action+Tab
- // keys (Not Alt+Tab which is KQS). The overview button on-screen in 3-button
- // nav is TYPE_TOGGLE.
- mKeyboardTaskFocusIndex = 0;
- break;
- default:
- // continue below to handle displaying Recents.
- }
- } else {
- createdRecentsView = visibleRecentsView;
- switch (cmd.type) {
- case TYPE_SHOW:
- // already visible
- return true;
- case TYPE_KEYBOARD_INPUT: {
- if (visibleRecentsView.isHandlingTouch()) {
- return true;
- }
- }
- case TYPE_HIDE: {
- if (visibleRecentsView.isHandlingTouch()) {
- return true;
- }
- mKeyboardTaskFocusIndex = INVALID_PAGE;
- int currentPage = visibleRecentsView.getNextPage();
- TaskView tv = (currentPage >= 0
- && currentPage < visibleRecentsView.getTaskViewCount())
- ? (TaskView) visibleRecentsView.getPageAt(currentPage)
- : null;
- return launchTask(visibleRecentsView, tv, cmd);
- }
- case TYPE_TOGGLE:
- return launchTask(visibleRecentsView, getNextTask(visibleRecentsView), cmd);
- case TYPE_HOME:
- visibleRecentsView.startHome();
- return true;
- }
- }
-
- if (createdRecentsView != null) {
- createdRecentsView.setKeyboardTaskFocusIndex(mKeyboardTaskFocusIndex);
- }
- // Handle recents view focus when launching from home
- Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- updateRecentsViewFocus(cmd);
- logShowOverviewFrom(cmd.type);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- Log.d(TAG, "switching to Overview state - onAnimationEnd: " + cmd);
- super.onAnimationEnd(animation);
- onRecentsViewFocusUpdated(cmd);
- scheduleNextTask(cmd);
- }
- };
- if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
- Log.d(TAG, "switching to Overview state - waiting: " + cmd);
- // If successfully switched, wait until animation finishes
- return false;
- }
-
- final T activity = activityInterface.getCreatedContainer();
- if (activity != null) {
- InteractionJankMonitorWrapper.begin(
- activity.getRootView(),
- Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
- }
-
- GestureState gestureState = mService.createGestureState(GestureState.DEFAULT_STATE,
- GestureState.TrackpadGestureType.NONE);
- gestureState.setHandlingAtomicEvent(true);
- AbsSwipeUpHandler interactionHandler = mService.getSwipeUpHandlerFactory()
- .newHandler(gestureState, cmd.createTime);
- interactionHandler.setGestureEndCallback(
- () -> onTransitionComplete(cmd, interactionHandler));
- interactionHandler.initWhenReady("OverviewCommandHelper: cmd.type=" + cmd.type);
-
- RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() {
- @Override
- public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets) {
- updateRecentsViewFocus(cmd);
- logShowOverviewFrom(cmd.type);
- activityInterface.runOnInitBackgroundStateUI(() ->
- interactionHandler.onGestureEnded(0, new PointF()));
- cmd.removeListener(this);
- }
-
- @Override
- public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
- interactionHandler.onGestureCancelled();
- cmd.removeListener(this);
-
- T createdActivity = activityInterface.getCreatedContainer();
- if (createdActivity == null) {
- return;
- }
- if (createdRecentsView != null) {
- createdRecentsView.onRecentsAnimationComplete();
- }
- }
- };
-
- if (visibleRecentsView != null) {
- visibleRecentsView.moveRunningTaskToFront();
- }
- if (mTaskAnimationManager.isRecentsAnimationRunning()) {
- cmd.mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(gestureState);
- cmd.mActiveCallbacks.addListener(interactionHandler);
- mTaskAnimationManager.notifyRecentsAnimationState(interactionHandler);
- interactionHandler.onGestureStarted(true /*isLikelyToStartNewTask*/);
-
- cmd.mActiveCallbacks.addListener(recentAnimListener);
- mTaskAnimationManager.notifyRecentsAnimationState(recentAnimListener);
- } else {
- Intent intent = new Intent(interactionHandler.getLaunchIntent());
- intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, gestureState.getGestureId());
- cmd.mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(
- gestureState, intent, interactionHandler);
- interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/);
- cmd.mActiveCallbacks.addListener(recentAnimListener);
- }
- Trace.beginAsyncSection(TRANSITION_NAME, 0);
- Log.d(TAG, "switching via recents animation - onGestureStarted: " + cmd);
- return false;
- }
-
- private void onTransitionComplete(CommandInfo cmd, AbsSwipeUpHandler handler) {
- Log.d(TAG, "switching via recents animation - onTransitionComplete: " + cmd);
- cmd.removeListener(handler);
- Trace.endAsyncSection(TRANSITION_NAME, 0);
- onRecentsViewFocusUpdated(cmd);
- scheduleNextTask(cmd);
- }
-
- private void updateRecentsViewFocus(CommandInfo cmd) {
- RecentsView recentsView =
- mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
- if (recentsView == null || (cmd.type != TYPE_KEYBOARD_INPUT && cmd.type != TYPE_HIDE
- && cmd.type != TYPE_SHOW)) {
- return;
- }
- // When the overview is launched via alt tab (cmd type is TYPE_KEYBOARD_INPUT),
- // the touch mode somehow is not change to false by the Android framework.
- // The subsequent tab to go through tasks in overview can only be dispatched to
- // focuses views, while focus can only be requested in
- // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
- // here we launch overview with live tile.
- recentsView.getViewRootImpl().touchModeChanged(false);
- // Ensure that recents view has focus so that it receives the followup key inputs
- if (requestFocus(recentsView.getTaskViewAt(mKeyboardTaskFocusIndex))) {
- return;
- }
- if (requestFocus(recentsView.getNextTaskView())) {
- return;
- }
- if (requestFocus(recentsView.getTaskViewAt(0))) {
- return;
- }
- requestFocus(recentsView);
- }
-
- private void onRecentsViewFocusUpdated(CommandInfo cmd) {
- RecentsView recentsView =
- mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
- if (recentsView == null
- || cmd.type != TYPE_HIDE
- || mKeyboardTaskFocusIndex == INVALID_PAGE) {
- return;
- }
- recentsView.setKeyboardTaskFocusIndex(INVALID_PAGE);
- recentsView.setCurrentPage(mKeyboardTaskFocusIndex);
- mKeyboardTaskFocusIndex = INVALID_PAGE;
- }
-
- private boolean requestFocus(@Nullable View taskView) {
- if (taskView == null) {
- return false;
- }
- taskView.post(() -> {
- taskView.requestFocus();
- taskView.requestAccessibilityFocus();
- });
- return true;
- }
-
- private <T extends StatefulActivity<?> & RecentsViewContainer>
- void logShowOverviewFrom(int cmdType) {
- BaseActivityInterface<?, T> activityInterface =
- mOverviewComponentObserver.getActivityInterface();
- var container = activityInterface.getCreatedContainer();
- if (container != null) {
- StatsLogManager.LauncherEvent event;
- switch (cmdType) {
- case TYPE_SHOW -> event = LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT;
- case TYPE_HIDE ->
- event = LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH;
- case TYPE_TOGGLE -> event = LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON;
- default -> {
- return;
- }
- }
-
- StatsLogManager.newInstance(container.asContext())
- .logger()
- .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
- .setTaskSwitcherContainer(
- LauncherAtom.TaskSwitcherContainer.getDefaultInstance())
- .build())
- .log(event);
- }
- }
-
- public void dump(PrintWriter pw) {
- pw.println("OverviewCommandHelper:");
- pw.println(" mPendingCommands=" + mPendingCommands.size());
- if (!mPendingCommands.isEmpty()) {
- pw.println(" pendingCommandType=" + mPendingCommands.get(0).type);
- }
- pw.println(" mKeyboardTaskFocusIndex=" + mKeyboardTaskFocusIndex);
- pw.println(" mWaitForToggleCommandComplete=" + mWaitForToggleCommandComplete);
- }
-
- private static class CommandInfo {
- public final long createTime = SystemClock.elapsedRealtime();
- public final int type;
- RecentsAnimationCallbacks mActiveCallbacks;
-
- CommandInfo(int type) {
- this.type = type;
- }
-
- void removeListener(RecentsAnimationListener listener) {
- if (mActiveCallbacks != null) {
- mActiveCallbacks.removeListener(listener);
- }
- }
-
- @NonNull
- @Override
- public String toString() {
- return "CommandInfo("
- + "type=" + type + ", "
- + "createTime=" + createTime + ", "
- + "mActiveCallbacks=" + mActiveCallbacks
- + ")";
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
new file mode 100644
index 0000000..f92c557
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -0,0 +1,569 @@
+/*
+ * Copyright (C) 2018 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.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.content.Intent
+import android.graphics.PointF
+import android.os.SystemClock
+import android.os.Trace
+import android.util.Log
+import android.view.View
+import androidx.annotation.BinderThread
+import androidx.annotation.UiThread
+import androidx.annotation.VisibleForTesting
+import com.android.internal.jank.Cuj
+import com.android.launcher3.Flags.enableOverviewCommandHelperTimeout
+import com.android.launcher3.PagedView
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.RunnableList
+import com.android.launcher3.util.coroutines.DispatcherProvider
+import com.android.launcher3.util.coroutines.ProductionDispatchers
+import com.android.quickstep.OverviewCommandHelper.CommandInfo.CommandStatus
+import com.android.quickstep.OverviewCommandHelper.CommandType.HIDE
+import com.android.quickstep.OverviewCommandHelper.CommandType.HOME
+import com.android.quickstep.OverviewCommandHelper.CommandType.KEYBOARD_INPUT
+import com.android.quickstep.OverviewCommandHelper.CommandType.SHOW
+import com.android.quickstep.OverviewCommandHelper.CommandType.TOGGLE
+import com.android.quickstep.util.ActiveGestureLog
+import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.RecentsViewContainer
+import com.android.quickstep.views.TaskView
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper
+import java.io.PrintWriter
+import java.util.concurrent.ConcurrentLinkedDeque
+import kotlin.coroutines.resume
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.ensureActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withTimeout
+
+/** Helper class to handle various atomic commands for switching between Overview. */
+class OverviewCommandHelper
+@JvmOverloads
+constructor(
+ private val touchInteractionService: TouchInteractionService,
+ private val overviewComponentObserver: OverviewComponentObserver,
+ private val taskAnimationManager: TaskAnimationManager,
+ private val dispatcherProvider: DispatcherProvider = ProductionDispatchers,
+) {
+ private val coroutineScope = CoroutineScope(SupervisorJob() + dispatcherProvider.default)
+
+ private val commandQueue = ConcurrentLinkedDeque<CommandInfo>()
+
+ /**
+ * Index of the TaskView that should be focused when launching Overview. Persisted so that we do
+ * not lose the focus across multiple calls of [OverviewCommandHelper.executeCommand] for the
+ * same command
+ */
+ private var keyboardTaskFocusIndex = -1
+
+ /**
+ * Whether we should incoming toggle commands while a previous toggle command is still ongoing.
+ * This serves as a rate-limiter to prevent overlapping animations that can clobber each other
+ * and prevent clean-up callbacks from running. This thus prevents a recurring set of bugs with
+ * janky recents animations and unresponsive home and overview buttons.
+ */
+ private var waitForToggleCommandComplete = false
+
+ private val activityInterface: BaseActivityInterface<*, *>
+ get() = overviewComponentObserver.activityInterface
+
+ private val visibleRecentsView: RecentsView<*, *>?
+ get() = activityInterface.getVisibleRecentsView<RecentsView<*, *>>()
+
+ /**
+ * Adds a command to be executed next, after all pending tasks are completed. Max commands that
+ * can be queued is [.MAX_QUEUE_SIZE]. Requests after reaching that limit will be silently
+ * dropped.
+ */
+ @BinderThread
+ fun addCommand(type: CommandType): CommandInfo? {
+ if (commandQueue.size >= MAX_QUEUE_SIZE) {
+ Log.d(TAG, "command not added: $type - queue is full ($commandQueue).")
+ return null
+ }
+
+ val command = CommandInfo(type)
+ commandQueue.add(command)
+ Log.d(TAG, "command added: $command")
+
+ if (commandQueue.size == 1) {
+ Log.d(TAG, "execute: $command - queue size: ${commandQueue.size}")
+ if (enableOverviewCommandHelperTimeout()) {
+ coroutineScope.launch(dispatcherProvider.main) { processNextCommand() }
+ } else {
+ Executors.MAIN_EXECUTOR.execute { processNextCommand() }
+ }
+ } else {
+ Log.d(TAG, "not executed: $command - queue size: ${commandQueue.size}")
+ }
+
+ return command
+ }
+
+ fun canStartHomeSafely(): Boolean = commandQueue.isEmpty() || commandQueue.first().type == HOME
+
+ /** Clear pending or completed commands from the queue */
+ fun clearPendingCommands() {
+ Log.d(TAG, "clearing pending commands: $commandQueue")
+ commandQueue.removeAll { it.status != CommandStatus.PROCESSING }
+ }
+
+ /**
+ * Executes the next command from the queue. If the command finishes immediately (returns true),
+ * it continues to execute the next command, until the queue is empty of a command defer's its
+ * completion (returns false).
+ */
+ @UiThread
+ private fun processNextCommand() {
+ val command: CommandInfo =
+ commandQueue.firstOrNull()
+ ?: run {
+ Log.d(TAG, "no pending commands to be executed.")
+ return
+ }
+
+ command.status = CommandStatus.PROCESSING
+ Log.d(TAG, "executing command: $command")
+
+ if (enableOverviewCommandHelperTimeout()) {
+ coroutineScope.launch(dispatcherProvider.main) {
+ withTimeout(QUEUE_WAIT_DURATION_IN_MS) {
+ executeCommandSuspended(command)
+ ensureActive()
+ onCommandFinished(command)
+ }
+ }
+ } else {
+ val result = executeCommand(command, onCallbackResult = { onCommandFinished(command) })
+ Log.d(TAG, "command executed: $command with result: $result")
+ if (result) {
+ onCommandFinished(command)
+ } else {
+ Log.d(TAG, "waiting for command callback: $command")
+ }
+ }
+ }
+
+ /**
+ * Executes the task and returns true if next task can be executed. If false, then the next task
+ * is deferred until [.scheduleNextTask] is called
+ */
+ @VisibleForTesting
+ fun executeCommand(command: CommandInfo, onCallbackResult: () -> Unit): Boolean {
+ // This shouldn't happen if we execute 1 command per time.
+ if (waitForToggleCommandComplete && command.type == TOGGLE) {
+ Log.d(TAG, "executeCommand: $command - waiting for toggle command complete")
+ return true
+ }
+
+ val recentsView = visibleRecentsView
+ Log.d(TAG, "executeCommand: $command - visibleRecentsView: $recentsView")
+ return if (recentsView != null) {
+ executeWhenRecentsIsVisible(command, recentsView, onCallbackResult)
+ } else {
+ executeWhenRecentsIsNotVisible(command, onCallbackResult)
+ }
+ }
+
+ /**
+ * Executes the task and returns true if next task can be executed. If false, then the next task
+ * is deferred until [.scheduleNextTask] is called
+ */
+ private suspend fun executeCommandSuspended(command: CommandInfo) =
+ suspendCancellableCoroutine { continuation ->
+ fun processResult(isCompleted: Boolean) {
+ Log.d(TAG, "command executed: $command with result: $isCompleted")
+ if (isCompleted) {
+ continuation.resume(Unit)
+ } else {
+ Log.d(TAG, "waiting for command callback: $command")
+ }
+ }
+
+ val result = executeCommand(command, onCallbackResult = { processResult(true) })
+ processResult(result)
+
+ continuation.invokeOnCancellation { cancelCommand(command, it) }
+ }
+
+ private fun executeWhenRecentsIsVisible(
+ command: CommandInfo,
+ recentsView: RecentsView<*, *>,
+ onCallbackResult: () -> Unit,
+ ): Boolean =
+ when (command.type) {
+ SHOW -> true // already visible
+ KEYBOARD_INPUT,
+ HIDE -> {
+ if (recentsView.isHandlingTouch) {
+ true
+ } else {
+ keyboardTaskFocusIndex = PagedView.INVALID_PAGE
+ val currentPage = recentsView.nextPage
+ val taskView = recentsView.getTaskViewAt(currentPage)
+ launchTask(recentsView, taskView, command, onCallbackResult)
+ }
+ }
+ TOGGLE -> {
+ val taskView =
+ if (recentsView.runningTaskView == null) {
+ recentsView.getTaskViewAt(0)
+ } else {
+ recentsView.nextTaskView ?: recentsView.runningTaskView
+ }
+ launchTask(recentsView, taskView, command, onCallbackResult)
+ }
+ HOME -> {
+ recentsView.startHome()
+ true
+ }
+ }
+
+ private fun launchTask(
+ recents: RecentsView<*, *>,
+ taskView: TaskView?,
+ command: CommandInfo,
+ onCallbackResult: () -> Unit,
+ ): Boolean {
+ var callbackList: RunnableList? = null
+ if (taskView != null) {
+ waitForToggleCommandComplete = true
+ taskView.isEndQuickSwitchCuj = true
+ callbackList = taskView.launchWithAnimation()
+ }
+
+ if (callbackList != null) {
+ callbackList.add {
+ Log.d(TAG, "launching task callback: $command")
+ onCallbackResult()
+ waitForToggleCommandComplete = false
+ }
+ Log.d(TAG, "launching task - waiting for callback: $command")
+ return false
+ } else {
+ recents.startHome()
+ waitForToggleCommandComplete = false
+ return true
+ }
+ }
+
+ private fun executeWhenRecentsIsNotVisible(
+ command: CommandInfo,
+ onCallbackResult: () -> Unit,
+ ): Boolean {
+ val recentsViewContainer = activityInterface.getCreatedContainer() as? RecentsViewContainer
+ val recentsView: RecentsView<*, *>? = recentsViewContainer?.getOverviewPanel()
+ val deviceProfile = recentsViewContainer?.getDeviceProfile()
+ val uiController = activityInterface.getTaskbarController()
+ val allowQuickSwitch =
+ uiController != null &&
+ deviceProfile != null &&
+ (deviceProfile.isTablet || deviceProfile.isTwoPanels)
+
+ when (command.type) {
+ HIDE -> {
+ if (!allowQuickSwitch) return true
+ keyboardTaskFocusIndex = uiController!!.launchFocusedTask()
+ if (keyboardTaskFocusIndex == -1) return true
+ }
+ KEYBOARD_INPUT ->
+ if (allowQuickSwitch) {
+ uiController!!.openQuickSwitchView()
+ return true
+ } else {
+ keyboardTaskFocusIndex = 0
+ }
+ HOME -> {
+ ActiveGestureLog.INSTANCE.addLog("OverviewCommandHelper.executeCommand(HOME)")
+ // Although IActivityTaskManager$Stub$Proxy.startActivity is a slow binder call,
+ // we should still call it on main thread because launcher is waiting for
+ // ActivityTaskManager to resume it. Also calling startActivity() on bg thread
+ // could potentially delay resuming launcher. See b/348668521 for more details.
+ touchInteractionService.startActivity(overviewComponentObserver.homeIntent)
+ return true
+ }
+ SHOW ->
+ // When Recents is not currently visible, the command's type is SHOW
+ // when overview is triggered via the keyboard overview button or Action+Tab
+ // keys (Not Alt+Tab which is KQS). The overview button on-screen in 3-button
+ // nav is TYPE_TOGGLE.
+ keyboardTaskFocusIndex = 0
+ TOGGLE -> {}
+ }
+
+ recentsView?.setKeyboardTaskFocusIndex(keyboardTaskFocusIndex)
+ // Handle recents view focus when launching from home
+ val animatorListener: Animator.AnimatorListener =
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator) {
+ Log.d(TAG, "switching to Overview state - onAnimationStart: $command")
+ super.onAnimationStart(animation)
+ updateRecentsViewFocus(command)
+ logShowOverviewFrom(command.type)
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ Log.d(TAG, "switching to Overview state - onAnimationEnd: $command")
+ super.onAnimationEnd(animation)
+ onRecentsViewFocusUpdated(command)
+ onCallbackResult()
+ }
+ }
+ if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
+ Log.d(TAG, "switching to Overview state - waiting: $command")
+ // If successfully switched, wait until animation finishes
+ return false
+ }
+
+ val activity = activityInterface.getCreatedContainer()
+ if (activity != null) {
+ InteractionJankMonitorWrapper.begin(activity.rootView, Cuj.CUJ_LAUNCHER_QUICK_SWITCH)
+ }
+
+ val gestureState =
+ touchInteractionService.createGestureState(
+ GestureState.DEFAULT_STATE,
+ GestureState.TrackpadGestureType.NONE,
+ )
+ gestureState.isHandlingAtomicEvent = true
+ val interactionHandler =
+ touchInteractionService.swipeUpHandlerFactory.newHandler(
+ gestureState,
+ command.createTime,
+ )
+ interactionHandler.setGestureEndCallback {
+ onTransitionComplete(command, interactionHandler, onCallbackResult)
+ }
+ interactionHandler.initWhenReady("OverviewCommandHelper: command.type=${command.type}")
+
+ val recentAnimListener: RecentsAnimationCallbacks.RecentsAnimationListener =
+ object : RecentsAnimationCallbacks.RecentsAnimationListener {
+ override fun onRecentsAnimationStart(
+ controller: RecentsAnimationController,
+ targets: RecentsAnimationTargets,
+ ) {
+ Log.d(TAG, "recents animation started: $command")
+ updateRecentsViewFocus(command)
+ logShowOverviewFrom(command.type)
+ activityInterface.runOnInitBackgroundStateUI {
+ Log.d(TAG, "recents animation started - onInitBackgroundStateUI: $command")
+ interactionHandler.onGestureEnded(0f, PointF())
+ }
+ command.removeListener(this)
+ }
+
+ override fun onRecentsAnimationCanceled(
+ thumbnailDatas: HashMap<Int, ThumbnailData>
+ ) {
+ Log.d(TAG, "recents animation canceled: $command")
+ interactionHandler.onGestureCancelled()
+ command.removeListener(this)
+
+ activityInterface.getCreatedContainer() ?: return
+ recentsView?.onRecentsAnimationComplete()
+ }
+ }
+
+ if (taskAnimationManager.isRecentsAnimationRunning) {
+ command.setAnimationCallbacks(
+ taskAnimationManager.continueRecentsAnimation(gestureState)
+ )
+ command.addListener(interactionHandler)
+ taskAnimationManager.notifyRecentsAnimationState(interactionHandler)
+ interactionHandler.onGestureStarted(true /*isLikelyToStartNewTask*/)
+
+ command.addListener(recentAnimListener)
+ taskAnimationManager.notifyRecentsAnimationState(recentAnimListener)
+ } else {
+ val intent =
+ Intent(interactionHandler.getLaunchIntent())
+ .putExtra(ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID, gestureState.gestureId)
+ command.setAnimationCallbacks(
+ taskAnimationManager.startRecentsAnimation(gestureState, intent, interactionHandler)
+ )
+ interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/)
+ command.addListener(recentAnimListener)
+ }
+ Trace.beginAsyncSection(TRANSITION_NAME, 0)
+ Log.d(TAG, "switching via recents animation - onGestureStarted: $command")
+ return false
+ }
+
+ private fun onTransitionComplete(
+ command: CommandInfo,
+ handler: AbsSwipeUpHandler<*, *, *>,
+ onCommandResult: () -> Unit,
+ ) {
+ Log.d(TAG, "switching via recents animation - onTransitionComplete: $command")
+ command.removeListener(handler)
+ Trace.endAsyncSection(TRANSITION_NAME, 0)
+ onRecentsViewFocusUpdated(command)
+ onCommandResult()
+ }
+
+ /** Called when the command finishes execution. */
+ private fun onCommandFinished(command: CommandInfo) {
+ command.status = CommandStatus.COMPLETED
+ if (commandQueue.firstOrNull() !== command) {
+ Log.d(
+ TAG,
+ "next task not scheduled. First pending command type " +
+ "is ${commandQueue.firstOrNull()} - command type is: $command",
+ )
+ return
+ }
+
+ Log.d(TAG, "command executed successfully! $command")
+ commandQueue.remove(command)
+ processNextCommand()
+ }
+
+ private fun cancelCommand(command: CommandInfo, throwable: Throwable?) {
+ command.status = CommandStatus.CANCELED
+ Log.e(TAG, "command cancelled: $command - $throwable")
+ commandQueue.remove(command)
+ processNextCommand()
+ }
+
+ private fun updateRecentsViewFocus(command: CommandInfo) {
+ val recentsView: RecentsView<*, *> = visibleRecentsView ?: return
+ if (command.type != KEYBOARD_INPUT && command.type != HIDE && command.type != SHOW) {
+ return
+ }
+
+ // When the overview is launched via alt tab (command type is TYPE_KEYBOARD_INPUT),
+ // the touch mode somehow is not change to false by the Android framework.
+ // The subsequent tab to go through tasks in overview can only be dispatched to
+ // focuses views, while focus can only be requested in
+ // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
+ // here we launch overview with live tile.
+ recentsView.viewRootImpl.touchModeChanged(false)
+ // Ensure that recents view has focus so that it receives the followup key inputs
+ // Stops requesting focused after first view gets focused.
+ recentsView.getTaskViewAt(keyboardTaskFocusIndex).requestFocus() ||
+ recentsView.nextTaskView.requestFocus() ||
+ recentsView.getTaskViewAt(0).requestFocus() ||
+ recentsView.requestFocus()
+ }
+
+ private fun onRecentsViewFocusUpdated(command: CommandInfo) {
+ val recentsView: RecentsView<*, *> = visibleRecentsView ?: return
+ if (command.type != HIDE || keyboardTaskFocusIndex == PagedView.INVALID_PAGE) {
+ return
+ }
+ recentsView.setKeyboardTaskFocusIndex(PagedView.INVALID_PAGE)
+ recentsView.currentPage = keyboardTaskFocusIndex
+ keyboardTaskFocusIndex = PagedView.INVALID_PAGE
+ }
+
+ private fun View?.requestFocus(): Boolean {
+ if (this == null) return false
+ post {
+ requestFocus()
+ requestAccessibilityFocus()
+ }
+ return true
+ }
+
+ private fun logShowOverviewFrom(commandType: CommandType) {
+ val container = activityInterface.getCreatedContainer() as? RecentsViewContainer ?: return
+ val event =
+ when (commandType) {
+ SHOW -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT
+ HIDE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH
+ TOGGLE -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON
+ else -> return
+ }
+ StatsLogManager.newInstance(container.asContext())
+ .logger()
+ .withContainerInfo(
+ LauncherAtom.ContainerInfo.newBuilder()
+ .setTaskSwitcherContainer(
+ LauncherAtom.TaskSwitcherContainer.getDefaultInstance()
+ )
+ .build()
+ )
+ .log(event)
+ }
+
+ fun dump(pw: PrintWriter) {
+ pw.println("OverviewCommandHelper:")
+ pw.println(" pendingCommands=${commandQueue.size}")
+ if (commandQueue.isNotEmpty()) {
+ pw.println(" pendingCommandType=${commandQueue.first().type}")
+ }
+ pw.println(" keyboardTaskFocusIndex=$keyboardTaskFocusIndex")
+ pw.println(" waitForToggleCommandComplete=$waitForToggleCommandComplete")
+ }
+
+ @VisibleForTesting
+ data class CommandInfo(
+ val type: CommandType,
+ var status: CommandStatus = CommandStatus.IDLE,
+ val createTime: Long = SystemClock.elapsedRealtime(),
+ private var animationCallbacks: RecentsAnimationCallbacks? = null,
+ ) {
+ fun setAnimationCallbacks(recentsAnimationCallbacks: RecentsAnimationCallbacks) {
+ this.animationCallbacks = recentsAnimationCallbacks
+ }
+
+ fun addListener(listener: RecentsAnimationCallbacks.RecentsAnimationListener) {
+ animationCallbacks?.addListener(listener)
+ }
+
+ fun removeListener(listener: RecentsAnimationCallbacks.RecentsAnimationListener?) {
+ animationCallbacks?.removeListener(listener)
+ }
+
+ enum class CommandStatus {
+ IDLE,
+ PROCESSING,
+ COMPLETED,
+ CANCELED,
+ }
+ }
+
+ enum class CommandType {
+ SHOW,
+ KEYBOARD_INPUT,
+ HIDE,
+ TOGGLE, // Navigate to Overview
+ HOME, // Navigate to Home
+ }
+
+ companion object {
+ private const val TAG = "OverviewCommandHelper"
+ private const val TRANSITION_NAME = "Transition:toOverview"
+
+ /**
+ * Use case for needing a queue is double tapping recents button in 3 button nav. Size of 2
+ * should be enough. We'll toss in one more because we're kind hearted.
+ */
+ private const val MAX_QUEUE_SIZE = 3
+ private const val QUEUE_WAIT_DURATION_IN_MS = 5000L
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index d82426f..ca19480 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -274,6 +274,15 @@
return mActivityInterface;
}
+ /**
+ * Get the current container control helper for managing interactions to the overview activity.
+ *
+ * @return the current container control helper
+ */
+ public BaseContainerInterface<?, ?> getContainerInterface() {
+ return mActivityInterface;
+ }
+
public void dump(PrintWriter pw) {
pw.println("OverviewComponentObserver:");
pw.println(" isDefaultHome=" + mIsDefaultHome);
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index b4b8c5b..49b6f57 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -6,7 +6,6 @@
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Rect;
import android.os.Bundle;
import androidx.annotation.Nullable;
@@ -15,11 +14,11 @@
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.DisplayController;
-import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
@@ -77,26 +76,20 @@
return response;
}
- case TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET: {
- if (!mDeviceProfile.isTablet) {
- return null;
- }
- Rect focusedTaskRect = new Rect();
- LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
- focusedTaskRect, RecentsPagedOrientationHandler.PORTRAIT);
- response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
- return response;
+ case TestProtocol.REQUEST_GET_OVERVIEW_TASK_SIZE: {
+ return getUIProperty(Bundle::putParcelable,
+ recentsViewContainer ->
+ recentsViewContainer.<RecentsView<?, ?>>getOverviewPanel()
+ .getLastComputedTaskSize(),
+ this::getRecentsViewContainer);
}
- case TestProtocol.REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET: {
- if (!mDeviceProfile.isTablet) {
- return null;
- }
- Rect gridTaskRect = new Rect();
- LauncherActivityInterface.INSTANCE.calculateGridTaskSize(mContext, mDeviceProfile,
- gridTaskRect, RecentsPagedOrientationHandler.PORTRAIT);
- response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, gridTaskRect);
- return response;
+ case TestProtocol.REQUEST_GET_OVERVIEW_GRID_TASK_SIZE: {
+ return getUIProperty(Bundle::putParcelable,
+ recentsViewContainer ->
+ recentsViewContainer.<RecentsView<?, ?>>getOverviewPanel()
+ .getLastComputedGridTaskSize(),
+ this::getRecentsViewContainer);
}
case TestProtocol.REQUEST_GET_OVERVIEW_PAGE_SPACING: {
@@ -221,6 +214,17 @@
}
}
+ private RecentsViewContainer getRecentsViewContainer() {
+ RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext);
+ OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads);
+ try {
+ return observer.getContainerInterface().getCreatedContainer();
+ } finally {
+ observer.onDestroy();
+ rads.destroy();
+ }
+ }
+
@Override
protected boolean isLauncherInitialized() {
return super.isLauncherInitialized() && TouchInteractionService.isInitialized();
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index e66da52..05bef35 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -20,7 +20,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
+import static com.android.wm.shell.shared.GroupedRecentTaskInfo.TYPE_FREEFORM;
import android.app.ActivityManager;
import android.app.KeyguardManager;
@@ -40,8 +40,8 @@
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 6d5cb4b..9c60693 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -63,6 +63,7 @@
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.desktop.DesktopRecentsTransitionController;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.statemanager.StateManager.StateHandler;
@@ -525,4 +526,10 @@
public boolean isRecentsViewVisible() {
return getStateManager().getState().isRecentsViewVisible();
}
+
+ @Nullable
+ @Override
+ public DesktopVisibilityController getDesktopVisibilityController() {
+ return mTISBindHelper.getDesktopVisibilityController();
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 32e2389..0c5806b 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -54,17 +54,14 @@
private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
private final SystemUiProxy mSystemUiProxy;
- private final boolean mAllowMinimizeSplitScreen;
// TODO(141886704): Remove these references when they are no longer needed
private RecentsAnimationController mController;
private boolean mCancelled;
- public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
- boolean allowMinimizeSplitScreen) {
+ public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy) {
mSystemUiProxy = systemUiProxy;
- mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
@UiThread
@@ -122,7 +119,7 @@
}
mController = new RecentsAnimationController(animationController,
- mAllowMinimizeSplitScreen, this::onAnimationFinished);
+ this::onAnimationFinished);
if (mCancelled) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
mController::finishAnimationToApp);
@@ -177,19 +174,7 @@
});
}
- @BinderThread
- @Override
- public boolean onSwitchToScreenshot(Runnable onFinished) {
- Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
- for (RecentsAnimationListener listener : getListeners()) {
- if (listener.onSwitchToScreenshot(onFinished)) return;
- }
- onFinished.run();
- });
- return true;
- }
-
- private final void onAnimationFinished(RecentsAnimationController controller) {
+ private void onAnimationFinished(RecentsAnimationController controller) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "RecentsAnimationCallbacks.onAnimationFinished",
@@ -219,7 +204,6 @@
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "RecentsAnimationCallbacks:");
- pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
pw.println(prefix + "\tmCancelled=" + mCancelled);
}
@@ -246,12 +230,5 @@
* Callback made when a task started from the recents is ready for an app transition.
*/
default void onTasksAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTarget) {}
-
- /**
- * @return whether this will call onFinished or not (onFinished should only be called once).
- */
- default boolean onSwitchToScreenshot(Runnable onFinished) {
- return false;
- }
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 1b05e28..190d526 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -17,14 +17,11 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION;
-import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
-import android.view.IRecentsAnimationController;
import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
import android.window.PictureInPictureSurfaceTransaction;
@@ -35,11 +32,11 @@
import com.android.internal.os.IResultReceiver;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
-import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.wm.shell.recents.IRecentsAnimationController;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -52,21 +49,17 @@
private static final String TAG = "RecentsAnimationController";
private final RecentsAnimationControllerCompat mController;
private final Consumer<RecentsAnimationController> mOnFinishedListener;
- private final boolean mAllowMinimizeSplitScreen;
private boolean mUseLauncherSysBarFlags = false;
- private boolean mSplitScreenMinimized = false;
private boolean mFinishRequested = false;
// Only valid when mFinishRequested == true.
private boolean mFinishTargetIsLauncher;
private RunnableList mPendingFinishCallbacks = new RunnableList();
public RecentsAnimationController(RecentsAnimationControllerCompat controller,
- boolean allowMinimizeSplitScreen,
Consumer<RecentsAnimationController> onFinishedListener) {
mController = controller;
mOnFinishedListener = onFinishedListener;
- mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
/**
@@ -85,42 +78,16 @@
if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
mUseLauncherSysBarFlags = useLauncherSysBarFlags;
UI_HELPER_EXECUTOR.execute(() -> {
- if (!ENABLE_SHELL_TRANSITIONS) {
- mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
- } else {
- try {
- WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
- useLauncherSysBarFlags);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to reach window manager", e);
- }
+ try {
+ WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
+ useLauncherSysBarFlags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to reach window manager", e);
}
});
}
}
- /**
- * Indicates that the gesture has crossed the window boundary threshold and we should minimize
- * if we are in splitscreen.
- */
- public void setSplitScreenMinimized(Context context, boolean splitScreenMinimized) {
- if (!mAllowMinimizeSplitScreen) {
- return;
- }
- if (mSplitScreenMinimized != splitScreenMinimized) {
- mSplitScreenMinimized = splitScreenMinimized;
- }
- }
-
- /**
- * Remove task remote animation target from
- * {@link RecentsAnimationCallbacks#onTasksAppeared}}.
- */
- @UiThread
- public void removeTaskTarget(int targetTaskId) {
- UI_HELPER_EXECUTOR.execute(() -> mController.removeTask(targetTaskId));
- }
-
@UiThread
public void finishAnimationToHome() {
finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
@@ -195,19 +162,6 @@
}
/**
- * @see IRecentsAnimationController#cleanupScreenshot()
- */
- @UiThread
- public void cleanupScreenshot() {
- UI_HELPER_EXECUTOR.execute(() -> {
- ActiveGestureLog.INSTANCE.addLog(
- "cleanupScreenshot",
- ActiveGestureErrorDetector.GestureEvent.CLEANUP_SCREENSHOT);
- mController.cleanupScreenshot();
- });
- }
-
- /**
* @see RecentsAnimationControllerCompat#detachNavigationBarFromApp
*/
@UiThread
@@ -216,14 +170,6 @@
}
/**
- * @see IRecentsAnimationController#animateNavigationBarToApp(long)
- */
- @UiThread
- public void animateNavigationBarToApp(long duration) {
- UI_HELPER_EXECUTOR.execute(() -> mController.animateNavigationBarToApp(duration));
- }
-
- /**
* @see IRecentsAnimationController#setWillFinishToHome(boolean)
*/
@UiThread
@@ -272,9 +218,7 @@
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "RecentsAnimationController:");
- pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
pw.println(prefix + "\tmUseLauncherSysBarFlags=" + mUseLauncherSysBarFlags);
- pw.println(prefix + "\tmSplitScreenMinimized=" + mSplitScreenMinimized);
pw.println(prefix + "\tmFinishRequested=" + mFinishRequested);
pw.println(prefix + "\tmFinishTargetIsLauncher=" + mFinishTargetIsLauncher);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index f902284..5131774 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -74,6 +74,7 @@
import com.android.quickstep.util.GestureExclusionManager;
import com.android.quickstep.util.GestureExclusionManager.ExclusionListener;
import com.android.quickstep.util.NavBarPosition;
+import com.android.systemui.shared.Flags;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -548,6 +549,13 @@
}
/**
+ * @return whether the Assistant gesture can be used in 3 button navigation mode.
+ */
+ public boolean supportsAssistantGestureInButtonNav() {
+ return Flags.threeButtonCornerSwipe();
+ }
+
+ /**
* @param ev An ACTION_DOWN motion event
* @return whether the given motion event can trigger the assistant over the current task.
*/
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index db03dac..a01ceb2 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -43,6 +43,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.recents.data.RecentTasksDataSource;
+import com.android.quickstep.recents.data.TaskVisualsChangeNotifier;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.TaskVisualsChangeListener;
@@ -65,7 +66,8 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
- TaskStackChangeListener, TaskVisualsChangeListener, SafeCloseable {
+ TaskStackChangeListener, TaskVisualsChangeListener, TaskVisualsChangeNotifier,
+ SafeCloseable {
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
@@ -287,6 +289,7 @@
/**
* Adds a listener for visuals changes
*/
+ @Override
public void addThumbnailChangeListener(TaskVisualsChangeListener listener) {
mThumbnailChangeListeners.add(listener);
}
@@ -294,6 +297,7 @@
/**
* Removes a previously added listener
*/
+ @Override
public void removeThumbnailChangeListener(TaskVisualsChangeListener listener) {
mThumbnailChangeListeners.remove(listener);
}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 3dec381..8adc11a 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,7 +17,7 @@
package com.android.quickstep;
import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
+import static com.android.wm.shell.shared.split.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
import android.app.WindowConfiguration;
import android.content.Context;
@@ -33,7 +33,7 @@
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
-import com.android.wm.shell.util.SplitBounds;
+import com.android.wm.shell.shared.split.SplitBounds;
import java.util.ArrayList;
import java.util.Arrays;
@@ -68,7 +68,7 @@
*/
public RemoteTargetGluer(Context context, BaseContainerInterface sizingStrategy) {
DesktopVisibilityController desktopVisibilityController =
- LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ sizingStrategy.getDesktopVisibilityController();
if (desktopVisibilityController != null) {
int visibleTasksCount = desktopVisibilityController.getVisibleDesktopTasksCount();
if (visibleTasksCount > 0) {
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 6f1ab7d..80c07196 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -41,6 +41,7 @@
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.systemui.shared.Flags;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -157,7 +158,7 @@
// Register for navigation mode changes
mDisplayController.addChangeListener(this);
DisplayController.Info info = mDisplayController.getInfo();
- onDisplayInfoChangedInternal(info, CHANGE_ALL, info.getNavigationMode().hasGestures);
+ onDisplayInfoChangedInternal(info, CHANGE_ALL, hasGestures(info.getNavigationMode()));
runOnDestroy(() -> mDisplayController.removeChangeListener(this));
mOrientationListener = new OrientationEventListener(mContext) {
@@ -229,7 +230,7 @@
* Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
*/
public void updateGestureTouchRegions() {
- if (!mMode.hasGestures) {
+ if (!hasGestures(mMode)) {
return;
}
@@ -268,7 +269,7 @@
| CHANGE_SUPPORTED_BOUNDS)) != 0) {
mDisplayRotation = info.rotation;
- if (mMode.hasGestures) {
+ if (hasGestures(mMode)) {
updateGestureTouchRegions();
mOrientationTouchTransformer.createOrAddTouchRegion(info);
mCurrentAppRotation = mDisplayRotation;
@@ -295,9 +296,9 @@
mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayController.getInfo(),
mContext.getResources());
- if (forceRegister || (!mMode.hasGestures && newMode.hasGestures)) {
+ if (forceRegister || (!hasGestures(mMode) && hasGestures(newMode))) {
setupOrientationSwipeHandler();
- } else if (mMode.hasGestures && !newMode.hasGestures) {
+ } else if (hasGestures(mMode) && !hasGestures(newMode)) {
destroyOrientationSwipeHandlerCallback();
}
@@ -399,7 +400,7 @@
}
public int getCurrentActiveRotation() {
- if (!mMode.hasGestures) {
+ if (!hasGestures(mMode)) {
// touch rotation should always match that of display for 3 button
return mDisplayRotation;
}
@@ -416,4 +417,8 @@
public OrientationTouchTransformer getOrientationTouchTransformer() {
return mOrientationTouchTransformer;
}
+
+ private boolean hasGestures(NavigationMode mode) {
+ return mode.hasGestures || (mode == THREE_BUTTONS && Flags.threeButtonCornerSwipe());
+ }
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 0c2f29b..b4bd3e3 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -43,11 +43,8 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
-import android.view.IRecentsAnimationController;
-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;
@@ -82,26 +79,29 @@
import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.bubbles.IBubbles;
import com.android.wm.shell.bubbles.IBubblesListener;
-import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.common.pip.IPip;
import com.android.wm.shell.common.pip.IPipAnimationListener;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.desktopmode.IDesktopMode;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
+import com.android.wm.shell.recents.IRecentsAnimationController;
+import com.android.wm.shell.recents.IRecentsAnimationRunner;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.IShellTransitions;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
+import com.android.wm.shell.shared.split.SplitBounds;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.splitscreen.ISplitSelectListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -240,6 +240,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 +905,47 @@
}
}
+ /**
+ * 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");
+ }
+ }
+
+ /** Tells SysUI to show the expanded view. */
+ public void showExpandedView() {
+ try {
+ if (mBubbles != null) {
+ mBubbles.showExpandedView();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to call showExpandedView");
+ }
+ }
+
//
// Splitscreen
//
@@ -1477,7 +1529,7 @@
// Aidl bundles need to explicitly set class loader
// https://developer.android.com/guide/components/aidl#Bundles
if (extras != null) {
- extras.setClassLoader(getClass().getClassLoader());
+ extras.setClassLoader(SplitBounds.class.getClassLoader());
}
listener.onAnimationStart(new RecentsAnimationControllerCompat(controller), apps,
wallpapers, homeContentInsets, minimizedHomeBounds, extras);
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index f414399..289a2c1 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;
@@ -58,9 +60,8 @@
import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
- public static final boolean ENABLE_SHELL_TRANSITIONS = true;
- public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
- && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
+ public static final boolean SHELL_TRANSITIONS_ROTATION =
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
private final Context mCtx;
private RecentsAnimationController mController;
@@ -110,8 +111,9 @@
*/
public void preloadRecentsAnimation(Intent intent) {
// Pass null animation handler to indicate this start is for preloading
- UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
- .startRecentsActivity(intent, 0, null, null, null));
+ UI_HELPER_EXECUTOR.execute(() -> {
+ ActivityManagerWrapper.getInstance().preloadRecentsActivity(intent);
+ });
}
boolean shouldIgnoreMotionEvents() {
@@ -157,8 +159,7 @@
final BaseContainerInterface containerInterface = gestureState.getContainerInterface();
mLastGestureState = gestureState;
- RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(
- getSystemUiProxy(), containerInterface.allowMinimizeSplitScreen());
+ RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(getSystemUiProxy());
mCallbacks = newCallbacks;
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
@@ -188,7 +189,7 @@
}
mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
- if (ENABLE_SHELL_TRANSITIONS && mTargets.hasRecents
+ if (mTargets.hasRecents
// The filtered (MODE_CLOSING) targets only contain 1 home activity.
&& mTargets.apps.length == 1
&& mTargets.apps[0].windowConfiguration.getActivityType()
@@ -288,78 +289,49 @@
true /*shown*/, null /* animatorHandler */);
}
if (mController != null) {
- if (mLastAppearedTaskTargets != null) {
- for (RemoteAnimationTarget lastTarget : mLastAppearedTaskTargets) {
- for (RemoteAnimationTarget appearedTarget : appearedTaskTargets) {
- if (lastTarget != null &&
- appearedTarget.taskId != lastTarget.taskId) {
- mController.removeTaskTarget(lastTarget.taskId);
- }
- }
- }
- }
mLastAppearedTaskTargets = appearedTaskTargets;
mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
}
}
-
- @Override
- public boolean onSwitchToScreenshot(Runnable onFinished) {
- if (!containerInterface.isInLiveTileMode()
- || containerInterface.getCreatedContainer() == null) {
- // No need to switch since tile is already a screenshot.
- onFinished.run();
- } else {
- final RecentsView recentsView =
- containerInterface.getCreatedContainer().getOverviewPanel();
- if (recentsView != null) {
- recentsView.switchToScreenshot(onFinished);
- } else {
- onFinished.run();
- }
- }
- return true;
- }
});
final long eventTime = gestureState.getSwipeUpStartTimeMs();
mCallbacks.addListener(gestureState);
mCallbacks.addListener(listener);
- if (ENABLE_SHELL_TRANSITIONS) {
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setPendingIntentBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
- // Use regular (non-transient) launch for all apps page to control IME.
- if (!containerInterface.allowAllAppsFromOverview()) {
- options.setTransientLaunch();
- }
- options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
- mRecentsAnimationStartPending = getSystemUiProxy()
- .startRecentsActivity(intent, options, mCallbacks);
- if (enableHandleDelayedGestureCallbacks()) {
- ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
- "TaskAnimationManager.startRecentsAnimation(shell transition path): ")
- .append("Setting mRecentsAnimationStartPending = ")
- .append(mRecentsAnimationStartPending));
- }
- } else {
- UI_HELPER_EXECUTOR.execute(
- () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
- intent,
- eventTime,
- mCallbacks,
- result -> {
- if (enableHandleDelayedGestureCallbacks()) {
- ActiveGestureLog.INSTANCE.addLog(
- new ActiveGestureLog.CompoundString(
- "TaskAnimationManager.startRecentsAnimation")
- .append("(legacy path): Setting ")
- .append("mRecentsAnimationStartPending = ")
- .append(result));
- }
- mRecentsAnimationStartPending = result;
- },
- MAIN_EXECUTOR.getHandler()));
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+ 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()) {
+ ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+ "TaskAnimationManager.startRecentsAnimation: ")
+ .append("Setting mRecentsAnimationStartPending = ")
+ .append(mRecentsAnimationStartPending));
}
gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
return mCallbacks;
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index dad34ac..785666f 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -315,12 +315,12 @@
boolean isTaskSplitNotSupported = !task.isDockable ||
(intentFlags & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
boolean hideForExistingMultiWindow = container.getDeviceProfile().isMultiWindowMode;
- boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
+ boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
boolean isTaskInExpectedScrollPosition =
recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
if (notEnoughTasksToSplit || isTaskSplitNotSupported || hideForExistingMultiWindow
- || (isFocusedTask && isTaskInExpectedScrollPosition)) {
+ || (isLargeTile && isTaskInExpectedScrollPosition)) {
return null;
}
@@ -340,11 +340,11 @@
DeviceProfile deviceProfile = container.getDeviceProfile();
final TaskView taskView = taskContainer.getTaskView();
final RecentsView recentsView = taskView.getRecentsView();
- boolean isLargeTileFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
+ boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
boolean isInExpectedScrollPosition =
recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
boolean shouldShowActionsButtonInstead =
- isLargeTileFocusedTask && isInExpectedScrollPosition;
+ isLargeTile && isInExpectedScrollPosition;
// No "save app pair" menu item if:
// - we are in 3p launcher
@@ -431,7 +431,7 @@
@Override
public void onClick(View view) {
- if (mTaskView.launchTaskAnimated() != null) {
+ if (mTaskView.launchAsStaticTile() != null) {
SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning(
mTaskView.getFirstTask().key.id);
}
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index 3c6c3e4..580dcc2 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -27,6 +27,7 @@
import com.android.launcher3.R;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.recents.data.HighResLoadingStateNotifier;
import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource;
import com.android.quickstep.util.TaskKeyByLastActiveTimeCache;
import com.android.quickstep.util.TaskKeyCache;
@@ -48,7 +49,7 @@
private final boolean mEnableTaskSnapshotPreloading;
private final Context mContext;
- public static class HighResLoadingState {
+ public static class HighResLoadingState implements HighResLoadingStateNotifier {
private boolean mForceHighResThumbnails;
private boolean mVisible;
private boolean mFlingingFast;
@@ -65,11 +66,13 @@
mForceHighResThumbnails = !supportsLowResThumbnails();
}
- public void addCallback(HighResLoadingStateChangedCallback callback) {
+ @Override
+ public void addCallback(@NonNull HighResLoadingStateChangedCallback callback) {
mCallbacks.add(callback);
}
- public void removeCallback(HighResLoadingStateChangedCallback callback) {
+ @Override
+ public void removeCallback(@NonNull HighResLoadingStateChangedCallback callback) {
mCallbacks.remove(callback);
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index bd44283..d8063ba 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));
+ }
}
}
@@ -300,14 +304,6 @@
}
}
});
- } else {
- // There is no transition animation for app launch from recent in live tile mode so
- // we have to trigger the navigation bar animation from system here.
- final RecentsAnimationController controller =
- recentsView.getRecentsAnimationController();
- if (controller != null) {
- controller.animateNavigationBarToApp(RECENTS_LAUNCH_DURATION);
- }
}
topMostSimulators = remoteTargetHandles;
}
@@ -558,7 +554,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 +584,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/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 5c940a3..44e55c3 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -30,7 +30,6 @@
import static com.android.launcher3.LauncherPrefs.backedUpItem;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
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.OnboardingPrefs.HOME_BOUNCE_SEEN;
@@ -49,16 +48,16 @@
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
+import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
import android.app.PendingIntent;
import android.app.Service;
@@ -89,14 +88,17 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ConstantItem;
import com.android.launcher3.EncryptionType;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.provider.RestoreDbTask;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarManager;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -107,8 +109,10 @@
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
+import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer;
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
@@ -223,7 +227,6 @@
@BinderThread
@Override
public void onTaskbarToggled() {
- if (!FeatureFlags.ENABLE_KEYBOARD_TASKBAR_TOGGLE.get()) return;
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
TaskbarActivityContext activityContext =
tis.mTaskbarManager.getCurrentActivityContext();
@@ -243,7 +246,7 @@
return;
}
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
- tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+ tis.mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
});
}
@@ -253,10 +256,9 @@
executeForTouchInteractionService(tis -> {
if (triggeredFromAltTab) {
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
- tis.mOverviewCommandHelper.addCommand(
- OverviewCommandHelper.TYPE_KEYBOARD_INPUT);
+ tis.mOverviewCommandHelper.addCommand(CommandType.KEYBOARD_INPUT);
} else {
- tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
+ tis.mOverviewCommandHelper.addCommand(CommandType.SHOW);
}
});
}
@@ -267,7 +269,7 @@
executeForTouchInteractionService(tis -> {
if (triggeredFromAltTab && !triggeredFromHomeKey) {
// onOverviewShownFromAltTab hides the overview and ends at the target app
- tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HIDE);
+ tis.mOverviewCommandHelper.addCommand(CommandType.HIDE);
}
});
}
@@ -376,6 +378,15 @@
));
}
+ @BinderThread
+ @Override
+ public void appTransitionPending(boolean pending) {
+ MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
+ executeForTaskbarManager(
+ taskbarManager -> taskbarManager.appTransitionPending(pending))
+ ));
+ }
+
/**
* Preloads the Overview activity.
* <p>
@@ -450,6 +461,18 @@
return tis.mTaskbarManager;
}
+ /**
+ * Returns the {@link DesktopVisibilityController}
+ * <p>
+ * Returns {@code null} if TouchInteractionService is not connected
+ */
+ @Nullable
+ public DesktopVisibilityController getDesktopVisibilityController() {
+ TouchInteractionService tis = mTis.get();
+ if (tis == null) return null;
+ return tis.mDesktopVisibilityController;
+ }
+
@VisibleForTesting
public void injectFakeTrackpadForTesting() {
TouchInteractionService tis = mTis.get();
@@ -592,12 +615,12 @@
private final TaskbarNavButtonCallbacks mNavCallbacks = new TaskbarNavButtonCallbacks() {
@Override
public void onNavigateHome() {
- mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+ mOverviewCommandHelper.addCommand(CommandType.HOME);
}
@Override
public void onToggleOverview() {
- mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+ mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
}
};
@@ -625,6 +648,8 @@
private NavigationMode mGestureStartNavMode = null;
+ private DesktopVisibilityController mDesktopVisibilityController;
+
@Override
public void onCreate() {
super.onCreate();
@@ -637,15 +662,15 @@
mAllAppsActionManager = new AllAppsActionManager(
this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
mInputManager = getSystemService(InputManager.class);
- if (ENABLE_TRACKPAD_GESTURE.get()) {
- mInputManager.registerInputDeviceListener(mInputDeviceListener,
- UI_HELPER_EXECUTOR.getHandler());
- int [] inputDevices = mInputManager.getInputDeviceIds();
- for (int inputDeviceId : inputDevices) {
- mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
- }
+ mInputManager.registerInputDeviceListener(mInputDeviceListener,
+ UI_HELPER_EXECUTOR.getHandler());
+ int [] inputDevices = mInputManager.getInputDeviceIds();
+ for (int inputDeviceId : inputDevices) {
+ mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
}
- mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks);
+ mDesktopVisibilityController = new DesktopVisibilityController(this);
+ mTaskbarManager = new TaskbarManager(
+ this, mAllAppsActionManager, mNavCallbacks, mDesktopVisibilityController);
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
@@ -672,8 +697,9 @@
private void initInputMonitor(String reason) {
disposeEventHandlers("Initializing input monitor due to: " + reason);
- if (mDeviceState.isButtonNavMode() && (!ENABLE_TRACKPAD_GESTURE.get()
- || mTrackpadsConnected.isEmpty())) {
+ if (mDeviceState.isButtonNavMode()
+ && !mDeviceState.supportsAssistantGestureInButtonNav()
+ && (mTrackpadsConnected.isEmpty())) {
return;
}
@@ -739,8 +765,8 @@
private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame);
- StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface()
- .getCreatedContainer();
+ StatefulActivity<?> newOverviewActivity =
+ mOverviewComponentObserver.getActivityInterface().getCreatedContainer();
if (newOverviewActivity != null) {
mTaskbarManager.setActivity(newOverviewActivity);
}
@@ -804,6 +830,7 @@
mTrackpadsConnected.clear();
mTaskbarManager.destroy();
+ mDesktopVisibilityController.onDestroy();
sConnected = false;
ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener);
@@ -855,7 +882,9 @@
.append("); cancelling gesture."),
NAVIGATION_MODE_SWITCHED);
event.setAction(ACTION_CANCEL);
- } else if (mDeviceState.isButtonNavMode() && !isTrackpadMotionEvent(event)) {
+ } else if (mDeviceState.isButtonNavMode()
+ && !mDeviceState.supportsAssistantGestureInButtonNav()
+ && !isTrackpadMotionEvent(event)) {
ActiveGestureLog.INSTANCE.addLog(new CompoundString("TIS.onInputEvent: ")
.append("Cannot process input event: ")
.append("using 3-button nav and event is not a trackpad event"));
@@ -901,11 +930,29 @@
boolean isOneHandedModeActive = mDeviceState.isOneHandedModeActive();
boolean isInSwipeUpTouchRegion = mRotationTouchHelper.isInSwipeUpTouchRegion(event);
TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+ BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null;
+ boolean isOnBubbles = bubbleControllers != null
+ && BubbleBarInputConsumer.isEventOnBubbles(tac, event);
if (isInSwipeUpTouchRegion && tac != null) {
tac.closeKeyboardQuickSwitchView();
}
- if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
- || isHoverActionWithoutConsumer) {
+ if (mDeviceState.isButtonNavMode()
+ && mDeviceState.supportsAssistantGestureInButtonNav()) {
+ reasonString.append("in three button mode which supports Assistant gesture");
+ // Consume gesture event for Assistant (all other gestures should do nothing).
+ if (mDeviceState.canTriggerAssistantAction(event)) {
+ reasonString.append(" and event can trigger assistant action")
+ .append(", consuming gesture for assistant action");
+ mGestureState =
+ createGestureState(mGestureState, getTrackpadGestureType(event));
+ mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
+ } else {
+ reasonString.append(" but event cannot trigger Assistant")
+ .append(", consuming gesture as no-op");
+ mUncheckedConsumer = InputConsumer.NO_OP;
+ }
+ } else if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
+ || isHoverActionWithoutConsumer || isOnBubbles) {
reasonString.append(!isOneHandedModeActive && isInSwipeUpTouchRegion
? "one handed mode is not active and event is in swipe up region"
: "isHoverActionWithoutConsumer == true")
@@ -926,8 +973,7 @@
: "event is a trackpad multi-finger swipe")
.append(" and event can trigger assistant action")
.append(", consuming gesture for assistant action");
- mGestureState = createGestureState(mGestureState,
- getTrackpadGestureType(event));
+ mGestureState = createGestureState(mGestureState, getTrackpadGestureType(event));
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
// should not interrupt it. QuickSwitch assumes that interruption can only
// happen if the next gesture is also quick switch.
@@ -1085,6 +1131,15 @@
private InputConsumer newConsumer(
GestureState previousGestureState, GestureState newGestureState, MotionEvent event) {
+ TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+ BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null;
+ if (bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event)) {
+ InputConsumer consumer = new BubbleBarInputConsumer(this, bubbleControllers,
+ mInputMonitorCompat);
+ logInputConsumerSelectionReason(consumer, newCompoundString(
+ "event is on bubbles, creating new input consumer"));
+ return consumer;
+ }
AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
if (progressProxy != null) {
InputConsumer consumer = new ProgressDelegateInputConsumer(
@@ -1149,7 +1204,6 @@
}
// If Taskbar is present, we listen for swipe or cursor hover events to unstash it.
- TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
if (tac != null && !(base instanceof AssistantInputConsumer)) {
// Present always on large screen or on small screen w/ flag
boolean useTaskbarConsumer = tac.getDeviceProfile().isTaskbarPresent
@@ -1180,7 +1234,8 @@
NavHandle navHandle = tac != null ? tac.getNavHandle()
: SystemUiProxy.INSTANCE.get(this);
if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()
- && navHandle.canNavHandleBeLongPressed()) {
+ && navHandle.canNavHandleBeLongPressed()
+ && !ignoreThreeFingerTrackpadForNavHandleLongPress(mGestureState)) {
reasonString.append(NEWLINE_PREFIX)
.append(reasonPrefix)
.append(SUBSTRING_PREFIX)
@@ -1212,7 +1267,7 @@
getBaseContext(), mDeviceState, mInputMonitorCompat);
}
- if (ENABLE_TRACKPAD_GESTURE.get() && mGestureState.isTrackpadGesture()
+ if (mGestureState.isTrackpadGesture()
&& canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) {
reasonString = newCompoundString(reasonPrefix)
.append(SUBSTRING_PREFIX)
@@ -1276,6 +1331,11 @@
return new CompoundString(NEWLINE_PREFIX).append(substring);
}
+ private boolean ignoreThreeFingerTrackpadForNavHandleLongPress(GestureState gestureState) {
+ return Flags.ignoreThreeFingerTrackpadForNavHandleLongPress()
+ && gestureState.isThreeFingerTrackpadGesture();
+ }
+
private void logInputConsumerSelectionReason(
InputConsumer consumer, CompoundString reasonString) {
ActiveGestureLog.INSTANCE.addLog(new CompoundString("setInputConsumer: ")
@@ -1617,6 +1677,7 @@
createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
}
mTaskbarManager.dumpLogs("", pw);
+ mDesktopVisibilityController.dumpLogs("", pw);
pw.println("AssistStateManager:");
AssistStateManager.INSTANCE.get(this).dump("\t", pw);
SystemUiProxy.INSTANCE.get(this).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/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
new file mode 100644
index 0000000..db29636
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.dagger;
+
+import com.android.quickstep.logging.LoggingModule;
+
+import dagger.Module;
+
+@Module(includes = {LoggingModule.class})
+public class QuickStepModule {
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index f4a2738..e67a9bc 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -253,6 +253,9 @@
}
setFreezeViewVisibility(true);
+ if (mContainer.getDesktopVisibilityController() != null) {
+ mContainer.getDesktopVisibilityController().onLauncherStateChanged(toState);
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
new file mode 100644
index 0000000..92031c5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
@@ -0,0 +1,147 @@
+/*
+ * 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.inputconsumers;
+
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleDragController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.quickstep.InputConsumer;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Listens for touch events on the bubble bar.
+ */
+public class BubbleBarInputConsumer implements InputConsumer {
+
+ private final BubbleStashController mBubbleStashController;
+ private final BubbleBarViewController mBubbleBarViewController;
+ private final BubbleDragController mBubbleDragController;
+ private final InputMonitorCompat mInputMonitorCompat;
+
+ private boolean mSwipeUpOnBubbleHandle;
+ private boolean mPassedTouchSlop;
+ private boolean mStashedOrCollapsedOnDown;
+
+ private final int mTouchSlop;
+ private final PointF mDownPos = new PointF();
+ private final PointF mLastPos = new PointF();
+ private final long mTimeForTap;
+ private int mActivePointerId = INVALID_POINTER_ID;
+
+ public BubbleBarInputConsumer(Context context, BubbleControllers bubbleControllers,
+ InputMonitorCompat inputMonitorCompat) {
+ mBubbleStashController = bubbleControllers.bubbleStashController;
+ mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
+ mBubbleDragController = bubbleControllers.bubbleDragController;
+ mInputMonitorCompat = inputMonitorCompat;
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ mTimeForTap = ViewConfiguration.getTapTimeout();
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_BUBBLE_BAR;
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ final int action = ev.getAction();
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mActivePointerId = ev.getPointerId(0);
+ mDownPos.set(ev.getX(), ev.getY());
+ mLastPos.set(mDownPos);
+ mStashedOrCollapsedOnDown = mBubbleStashController.isStashed() || isCollapsed();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == INVALID_POINTER_ID) {
+ break;
+ }
+ mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+
+ float dX = mLastPos.x - mDownPos.x;
+ float dY = mLastPos.y - mDownPos.y;
+ if (!mPassedTouchSlop) {
+ mPassedTouchSlop = Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
+ }
+ if (mStashedOrCollapsedOnDown && !mSwipeUpOnBubbleHandle && mPassedTouchSlop) {
+ boolean verticalGesture = Math.abs(dY) > Math.abs(dX);
+ if (verticalGesture && !mBubbleDragController.isDragging()) {
+ mSwipeUpOnBubbleHandle = true;
+ mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
+ // Bubbles is handling the swipe so make sure no one else gets it.
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
+ mInputMonitorCompat.pilferPointers();
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ boolean isWithinTapTime = ev.getEventTime() - ev.getDownTime() <= mTimeForTap;
+ if (isWithinTapTime && !mSwipeUpOnBubbleHandle && !mPassedTouchSlop
+ && mStashedOrCollapsedOnDown) {
+ // Taps on the handle / collapsed state should open the bar
+ mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
+ }
+ break;
+ }
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ cleanupAfterMotionEvent();
+ }
+ }
+
+ private void cleanupAfterMotionEvent() {
+ mPassedTouchSlop = false;
+ mSwipeUpOnBubbleHandle = false;
+ }
+
+ private boolean isCollapsed() {
+ return mBubbleStashController.isBubbleBarVisible()
+ && !mBubbleBarViewController.isExpanded();
+ }
+
+ /**
+ * Returns whether the event is occurring on a visible bubble bar or the bar handle.
+ */
+ public static boolean isEventOnBubbles(TaskbarActivityContext tac, MotionEvent ev) {
+ if (tac == null || !tac.isBubbleBarEnabled()) {
+ return false;
+ }
+ BubbleControllers controllers = tac.getBubbleControllers();
+ if (controllers == null || !controllers.bubbleBarViewController.hasBubbles()) {
+ return false;
+ }
+ if (controllers.bubbleStashController.isStashed()
+ && controllers.bubbleStashedHandleViewController.isPresent()) {
+ return controllers.bubbleStashedHandleViewController.get().isEventOverHandle(ev);
+ } else if (controllers.bubbleBarViewController.isBubbleBarVisible()) {
+ return controllers.bubbleBarViewController.isEventOverBubbleBar(ev);
+ }
+ return false;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index f264364..b66d4cb 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -24,7 +24,6 @@
import static com.android.quickstep.AbsSwipeUpHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import android.animation.Animator;
@@ -58,7 +57,6 @@
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
import java.util.HashMap;
@@ -213,15 +211,13 @@
// This will come back and cancel the interaction.
startHomeIntentSafely(mContext, mGestureState.getHomeIntent(), null, TAG);
mHomeLaunched = true;
- } else if (ENABLE_SHELL_TRANSITIONS) {
- if (mTaskAnimationManager.getCurrentCallbacks() != null) {
- if (mRecentsAnimationController != null) {
- finishRecentsAnimationForShell(dismissTask);
- } else {
- // the transition of recents animation hasn't started, wait for it
- mCancelWhenRecentsStart = true;
- mDismissTask = dismissTask;
- }
+ } else if (mTaskAnimationManager.getCurrentCallbacks() != null) {
+ if (mRecentsAnimationController != null) {
+ finishRecentsAnimationForShell(dismissTask);
+ } else {
+ // the transition of recents animation hasn't started, wait for it
+ mCancelWhenRecentsStart = true;
+ mDismissTask = dismissTask;
}
}
mStateCallback.setState(STATE_HANDLER_INVALIDATED);
@@ -278,9 +274,7 @@
}
private void endRemoteAnimation() {
- if (mHomeLaunched) {
- ActivityManagerWrapper.getInstance().cancelRecentsAnimation(false);
- } else if (mRecentsAnimationController != null) {
+ if (!mHomeLaunched && mRecentsAnimationController != null) {
mRecentsAnimationController.finishController(
false /* toRecents */, null /* callback */, false /* sendUserLeaveHint */);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 9a99d4a..9284e13 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -15,9 +15,7 @@
*/
package com.android.quickstep.inputconsumers;
-import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_MOVE;
-import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.launcher3.Flags.enableCursorHoverStates;
@@ -43,12 +41,12 @@
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarThresholdUtils;
import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
-import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.systemui.shared.system.InputMonitorCompat;
/**
@@ -69,9 +67,6 @@
private final int mTaskbarNavThresholdY;
private final boolean mIsTaskbarAllAppsOpen;
private boolean mHasPassedTaskbarNavThreshold;
- private boolean mIsInBubbleBarArea;
- private boolean mIsVerticalGestureOverBubbleBar;
- private boolean mIsPassedBubbleBarSlop;
private final int mTouchSlop;
private final PointF mDownPos = new PointF();
@@ -159,9 +154,6 @@
if (mTransitionCallback != null && !mIsTaskbarAllAppsOpen) {
mTransitionCallback.onActionDown();
}
- if (mIsTransientTaskbar && isInBubbleBarArea(x)) {
- mIsInBubbleBarArea = true;
- }
break;
case MotionEvent.ACTION_POINTER_UP:
int ptrIdx = ev.getActionIndex();
@@ -185,18 +177,6 @@
float dX = mLastPos.x - mDownPos.x;
float dY = mLastPos.y - mDownPos.y;
- if (!mIsPassedBubbleBarSlop && mIsInBubbleBarArea) {
- boolean passedSlop =
- Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
- if (passedSlop) {
- mIsPassedBubbleBarSlop = true;
- mIsVerticalGestureOverBubbleBar = Math.abs(dY) > Math.abs(dX);
- if (mIsVerticalGestureOverBubbleBar) {
- setActive(ev);
- }
- }
- }
-
if (mIsTransientTaskbar) {
boolean passedTaskbarNavThreshold = dY < 0
&& Math.abs(dY) >= mTaskbarNavThreshold;
@@ -204,11 +184,7 @@
if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold
&& !mGestureState.isInExtendedSlopRegion()) {
mHasPassedTaskbarNavThreshold = true;
- if (mIsInBubbleBarArea && mIsVerticalGestureOverBubbleBar) {
- mTaskbarActivityContext.onSwipeToOpenBubblebar();
- } else {
- mTaskbarActivityContext.onSwipeToUnstashTaskbar();
- }
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar();
}
if (dY < 0) {
@@ -225,46 +201,13 @@
break;
case MotionEvent.ACTION_BUTTON_RELEASE:
if (isStashedTaskbarHovered) {
- mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+ mOverviewCommandHelper.addCommand(CommandType.HOME);
}
break;
}
}
- boolean isMovingInBubbleBarArea = mIsInBubbleBarArea && ev.getAction() == ACTION_MOVE;
if (!isStashedTaskbarHovered) {
- // if we're moving in the bubble bar area but we haven't passed the slop yet, don't
- // propagate to the delegate, until we can determine the direction of the gesture.
- if (!isMovingInBubbleBarArea || mIsPassedBubbleBarSlop) {
- mDelegate.onMotionEvent(ev);
- }
- }
- } else if (mIsVerticalGestureOverBubbleBar) {
- // if we get here then this gesture is a vertical swipe over the bubble bar.
- // we're also active and there's no need to delegate any additional motion events. the
- // rest of the gesture will be handled here.
- switch (ev.getAction()) {
- case ACTION_MOVE:
- int pointerIndex = ev.findPointerIndex(mActivePointerId);
- if (pointerIndex == INVALID_POINTER_ID) {
- break;
- }
- mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
-
- float dY = mLastPos.y - mDownPos.y;
-
- // bubble bar swipe gesture uses the same threshold as the taskbar.
- boolean passedTaskbarNavThreshold = dY < 0
- && Math.abs(dY) >= mTaskbarNavThreshold;
-
- if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) {
- mHasPassedTaskbarNavThreshold = true;
- mTaskbarActivityContext.onSwipeToOpenBubblebar();
- }
- break;
- case ACTION_UP:
- case ACTION_CANCEL:
- cleanupAfterMotionEvent();
- break;
+ mDelegate.onMotionEvent(ev);
}
}
}
@@ -301,9 +244,6 @@
mTransitionCallback.onActionEnd();
}
mHasPassedTaskbarNavThreshold = false;
- mIsInBubbleBarArea = false;
- mIsVerticalGestureOverBubbleBar = false;
- mIsPassedBubbleBarSlop = false;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -313,23 +253,6 @@
mMotionMoveCount = 0;
}
- private boolean isInBubbleBarArea(float x) {
- if (mTaskbarActivityContext == null || !mIsTransientTaskbar) {
- return false;
- }
- BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers();
- if (controllers == null) {
- return false;
- }
- 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;
- }
- }
-
/**
* Listen for hover events for the stashed taskbar.
*
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
index 742b0fc..7a86db3 100644
--- a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -175,11 +173,8 @@
void setFakeTaskViewFillColor(@ColorInt int colorResId) {
mFullTaskView.setBackgroundColor(colorResId);
-
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()){
- mTopTaskView.getBackground().setTint(colorResId);
- mBottomTaskView.getBackground().setTint(colorResId);
- }
+ mTopTaskView.getBackground().setTint(colorResId);
+ mBottomTaskView.getBackground().setTint(colorResId);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 6757cd8..be7f8e5 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION;
import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE;
@@ -40,35 +39,29 @@
BackGestureTutorialController(BackGestureTutorialFragment fragment, TutorialType tutorialType) {
super(fragment, tutorialType);
// Set the Lottie animation colors specifically for the Back gesture
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- LottieAnimationColorUtils.updateToArgbColors(
- mAnimatedGestureDemonstration,
- Map.of(".onSurfaceBack", fragment.mRootView.mColorOnSurfaceBack,
- ".surfaceBack", fragment.mRootView.mColorSurfaceBack,
- ".secondaryBack", fragment.mRootView.mColorSecondaryBack));
+ LottieAnimationColorUtils.updateToArgbColors(
+ mAnimatedGestureDemonstration,
+ Map.of(".onSurfaceBack", fragment.mRootView.mColorOnSurfaceBack,
+ ".surfaceBack", fragment.mRootView.mColorSurfaceBack,
+ ".secondaryBack", fragment.mRootView.mColorSecondaryBack));
- LottieAnimationColorUtils.updateToArgbColors(
- mCheckmarkAnimation,
- Map.of(".checkmark",
- Utilities.isDarkTheme(mContext)
- ? fragment.mRootView.mColorOnSurfaceBack
- : fragment.mRootView.mColorSecondaryBack,
- ".checkmarkBackground", fragment.mRootView.mColorSurfaceBack));
- }
+ LottieAnimationColorUtils.updateToArgbColors(
+ mCheckmarkAnimation,
+ Map.of(".checkmark",
+ Utilities.isDarkTheme(mContext)
+ ? fragment.mRootView.mColorOnSurfaceBack
+ : fragment.mRootView.mColorSecondaryBack,
+ ".checkmarkBackground", fragment.mRootView.mColorSurfaceBack));
}
@Override
public int getIntroductionTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.back_gesture_tutorial_title
- : R.string.back_gesture_intro_title;
+ return R.string.back_gesture_tutorial_title;
}
@Override
public int getIntroductionSubtitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.back_gesture_tutorial_subtitle
- : R.string.back_gesture_intro_subtitle;
+ return R.string.back_gesture_tutorial_subtitle;
}
@Override
@@ -85,9 +78,7 @@
public int getSuccessFeedbackSubtitle() {
return mTutorialFragment.isAtFinalStep()
? R.string.back_gesture_feedback_complete_without_follow_up
- : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.back_gesture_feedback_complete_with_follow_up
- : R.string.back_gesture_feedback_complete_with_overview_follow_up;
+ : R.string.back_gesture_feedback_complete_with_follow_up;
}
@Override
@@ -128,20 +119,12 @@
@LayoutRes
int getMockAppTaskCurrentPageLayoutResId() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.back_gesture_tutorial_background
- : mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_tablet_mock_conversation
- : R.layout.gesture_tutorial_mock_conversation;
+ return R.layout.back_gesture_tutorial_background;
}
@LayoutRes
int getMockAppTaskPreviousPageLayoutResId() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.back_gesture_tutorial_background
- : mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_tablet_mock_conversation_list
- : R.layout.gesture_tutorial_mock_conversation_list;
+ return R.layout.back_gesture_tutorial_background;
}
@Override
@@ -214,17 +197,13 @@
}
private void handleBackAttempt(BackGestureResult result) {
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- resetViewsForBackGesture();
- }
+ resetViewsForBackGesture();
switch (result) {
case BACK_COMPLETED_FROM_LEFT:
case BACK_COMPLETED_FROM_RIGHT:
mTutorialFragment.releaseFeedbackAnimation();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mExitingAppView.setVisibility(View.GONE);
- }
+ mExitingAppView.setVisibility(View.GONE);
updateFakeAppTaskViewLayout(getMockAppTaskPreviousPageLayoutResId());
showSuccessFeedback();
break;
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
index 1b12be8..700fbf8 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
@@ -211,10 +209,8 @@
}
}
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mGestureCallback.onBackGestureProgress(ev.getX() - mDownPoint.x,
- ev.getY() - mDownPoint.y, mEdgeBackPanel.getIsLeftPanel());
- }
+ mGestureCallback.onBackGestureProgress(ev.getX() - mDownPoint.x,
+ ev.getY() - mDownPoint.y, mEdgeBackPanel.getIsLeftPanel());
// forward touch
mEdgeBackPanel.onMotionEvent(ev);
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 36ea926..bc5cc15 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -37,10 +37,10 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.TouchInteractionService.TISBinder;
import com.android.quickstep.interaction.TutorialController.TutorialType;
+import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.TISBindHelper;
import java.util.ArrayList;
@@ -54,8 +54,6 @@
static final String KEY_TUTORIAL_TYPE = "tutorial_type";
static final String KEY_GESTURE_COMPLETE = "gesture_complete";
static final String KEY_USE_TUTORIAL_MENU = "use_tutorial_menu";
- public static final double SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95;
- public static final double SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05;
@Nullable private TutorialType[] mTutorialSteps;
private GestureSandboxFragment mCurrentFragment;
@@ -80,9 +78,7 @@
Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState;
boolean gestureComplete = args != null && args.getBoolean(KEY_GESTURE_COMPLETE, false);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- && args != null
- && args.getBoolean(KEY_USE_TUTORIAL_MENU, false)) {
+ if (args != null && args.getBoolean(KEY_USE_TUTORIAL_MENU, false)) {
mTutorialSteps = null;
TutorialType tutorialTypeOverride = (TutorialType) args.get(KEY_TUTORIAL_TYPE);
mCurrentFragment = tutorialTypeOverride == null
@@ -102,9 +98,7 @@
.add(R.id.gesture_tutorial_fragment_container, mCurrentFragment)
.commit();
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- correctUserOrientation();
- }
+ correctUserOrientation();
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
initWindowInsets();
@@ -116,9 +110,7 @@
super.onConfigurationChanged(newConfig);
// Ensure the prompt to rotate the screen is updated
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- correctUserOrientation();
- }
+ correctUserOrientation();
}
private void initWindowInsets() {
@@ -170,10 +162,7 @@
getApplicationContext()).getDeviceProfile(this);
if (deviceProfile.isTablet) {
// The tutorial will work in either orientation if the height and width are similar
- boolean isAspectRatioSquare =
- deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
- && deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND;
- boolean showRotationPrompt = !isAspectRatioSquare
+ boolean showRotationPrompt = !LayoutUtils.isAspectRatioSquare(deviceProfile.aspectRatio)
&& getResources().getConfiguration().orientation
== ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 1129e02..bf4eaf2 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.graphics.PointF;
import com.android.launcher3.R;
@@ -34,35 +32,29 @@
super(fragment, tutorialType);
// Set the Lottie animation colors specifically for the Home gesture
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- LottieAnimationColorUtils.updateToArgbColors(
- mAnimatedGestureDemonstration,
- Map.of(".onSurfaceHome", fragment.mRootView.mColorOnSurfaceHome,
- ".surfaceHome", fragment.mRootView.mColorSurfaceHome,
- ".secondaryHome", fragment.mRootView.mColorSecondaryHome));
+ LottieAnimationColorUtils.updateToArgbColors(
+ mAnimatedGestureDemonstration,
+ Map.of(".onSurfaceHome", fragment.mRootView.mColorOnSurfaceHome,
+ ".surfaceHome", fragment.mRootView.mColorSurfaceHome,
+ ".secondaryHome", fragment.mRootView.mColorSecondaryHome));
- LottieAnimationColorUtils.updateToArgbColors(
- mCheckmarkAnimation,
- Map.of(".checkmark",
- Utilities.isDarkTheme(mContext)
- ? fragment.mRootView.mColorOnSurfaceHome
- : fragment.mRootView.mColorSecondaryHome,
- ".checkmarkBackground", fragment.mRootView.mColorSurfaceHome));
- }
+ LottieAnimationColorUtils.updateToArgbColors(
+ mCheckmarkAnimation,
+ Map.of(".checkmark",
+ Utilities.isDarkTheme(mContext)
+ ? fragment.mRootView.mColorOnSurfaceHome
+ : fragment.mRootView.mColorSecondaryHome,
+ ".checkmarkBackground", fragment.mRootView.mColorSurfaceHome));
}
@Override
public int getIntroductionTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.home_gesture_tutorial_title
- : R.string.home_gesture_intro_title;
+ return R.string.home_gesture_tutorial_title;
}
@Override
public int getIntroductionSubtitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.home_gesture_tutorial_subtitle
- : R.string.home_gesture_intro_subtitle;
+ return R.string.home_gesture_tutorial_subtitle;
}
@Override
@@ -72,9 +64,7 @@
@Override
public int getSuccessFeedbackTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.home_gesture_tutorial_success
- : R.string.gesture_tutorial_nice;
+ return R.string.home_gesture_tutorial_success;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index a04dd44..e45f8d8 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -16,7 +16,6 @@
package com.android.quickstep.interaction;
import static com.android.app.animation.Interpolators.ACCELERATE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -49,34 +48,28 @@
super(fragment, tutorialType);
// Set the Lottie animation colors specifically for the Overview gesture
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- LottieAnimationColorUtils.updateToArgbColors(
- mAnimatedGestureDemonstration,
- Map.of(".onSurfaceOverview", fragment.mRootView.mColorOnSurfaceOverview,
- ".surfaceOverview", fragment.mRootView.mColorSurfaceOverview,
- ".secondaryOverview", fragment.mRootView.mColorSecondaryOverview));
+ LottieAnimationColorUtils.updateToArgbColors(
+ mAnimatedGestureDemonstration,
+ Map.of(".onSurfaceOverview", fragment.mRootView.mColorOnSurfaceOverview,
+ ".surfaceOverview", fragment.mRootView.mColorSurfaceOverview,
+ ".secondaryOverview", fragment.mRootView.mColorSecondaryOverview));
- LottieAnimationColorUtils.updateToArgbColors(
- mCheckmarkAnimation,
- Map.of(".checkmark",
- Utilities.isDarkTheme(mContext)
- ? fragment.mRootView.mColorOnSurfaceOverview
- : fragment.mRootView.mColorSecondaryOverview,
- ".checkmarkBackground", fragment.mRootView.mColorSurfaceOverview));
- }
+ LottieAnimationColorUtils.updateToArgbColors(
+ mCheckmarkAnimation,
+ Map.of(".checkmark",
+ Utilities.isDarkTheme(mContext)
+ ? fragment.mRootView.mColorOnSurfaceOverview
+ : fragment.mRootView.mColorSecondaryOverview,
+ ".checkmarkBackground", fragment.mRootView.mColorSurfaceOverview));
}
@Override
public int getIntroductionTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.overview_gesture_tutorial_title
- : R.string.overview_gesture_intro_title;
+ return R.string.overview_gesture_tutorial_title;
}
@Override
public int getIntroductionSubtitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.overview_gesture_tutorial_subtitle
- : R.string.overview_gesture_intro_subtitle;
+ return R.string.overview_gesture_tutorial_subtitle;
}
@Override
@@ -86,9 +79,7 @@
@Override
public int getSuccessFeedbackTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.overview_gesture_tutorial_success
- : R.string.gesture_tutorial_nice;
+ return R.string.overview_gesture_tutorial_success;
}
@Override
@@ -168,10 +159,7 @@
@Override
protected int getMockPreviousAppTaskThumbnailColor() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? mTutorialFragment.mRootView.mColorSurfaceContainer
- : mContext.getResources().getColor(
- R.color.gesture_tutorial_fake_previous_task_view_color);
+ return mTutorialFragment.mRootView.mColorSurfaceContainer;
}
@Override
@@ -224,11 +212,8 @@
case OVERVIEW_GESTURE_COMPLETED:
setGestureCompleted();
mTutorialFragment.releaseFeedbackAnimation();
- animateTaskViewToOverview(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get());
+ animateTaskViewToOverview(true);
onMotionPaused(true /*arbitrary value*/);
- if (!ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- showSuccessFeedback();
- }
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
diff --git a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
index affedb9..d733267 100644
--- a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
+++ b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
@@ -15,16 +15,12 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Insets;
-import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.View;
import android.view.WindowInsets;
import android.widget.RelativeLayout;
@@ -39,10 +35,6 @@
/** Root layout that TutorialFragment uses to intercept motion events. */
public class RootSandboxLayout extends RelativeLayout {
- private final Rect mTempStepIndicatorBounds = new Rect();
- private final Rect mTempInclusionBounds = new Rect();
- private final Rect mTempExclusionBounds = new Rect();
-
@ColorInt final int mColorSurfaceContainer;
@ColorInt final int mColorOnSurfaceHome;
@ColorInt final int mColorSurfaceHome;
@@ -54,11 +46,6 @@
@ColorInt final int mColorSurfaceOverview;
@ColorInt final int mColorSecondaryOverview;
- private View mFeedbackView;
- private View mTutorialStepView;
- private View mSkipButton;
- private View mDoneButton;
-
public RootSandboxLayout(Context context) {
this(context, null);
}
@@ -123,56 +110,4 @@
return getHeight() + insets.top + insets.bottom;
}
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- return;
- }
- mFeedbackView = findViewById(R.id.gesture_tutorial_fragment_feedback_view);
- mTutorialStepView =
- mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_tutorial_step);
- mSkipButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_close_button);
- mDoneButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_action_button);
-
- mFeedbackView.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- if (mSkipButton.getVisibility() != VISIBLE
- && mDoneButton.getVisibility() != VISIBLE) {
- return;
- }
- // Either the skip or the done button is ever shown at once, never both.
- boolean showingSkipButton = mSkipButton.getVisibility() == VISIBLE;
- boolean isRTL = Utilities.isRtl(getContext().getResources());
- updateTutorialStepViewTranslation(
- showingSkipButton ? mSkipButton : mDoneButton,
- // Translate the step indicator away from whichever button is being
- // shown. The skip button in on the left in LTR or on the right in RTL.
- // The done button is on the right in LTR or left in RTL.
- (showingSkipButton && !isRTL) || (!showingSkipButton && isRTL));
- });
- }
-
- private void updateTutorialStepViewTranslation(
- @NonNull View anchorView, boolean translateToRight) {
- mTempStepIndicatorBounds.set(
- mTutorialStepView.getLeft(),
- mTutorialStepView.getTop(),
- mTutorialStepView.getRight(),
- mTutorialStepView.getBottom());
- mTempInclusionBounds.set(0, 0, mFeedbackView.getWidth(), mFeedbackView.getHeight());
- mTempExclusionBounds.set(
- anchorView.getLeft(),
- anchorView.getTop(),
- anchorView.getRight(),
- anchorView.getBottom());
-
- Utilities.translateOverlappingView(
- mTutorialStepView,
- mTempStepIndicatorBounds,
- mTempInclusionBounds,
- mTempExclusionBounds,
- translateToRight ? Utilities.TRANSLATE_RIGHT : Utilities.TRANSLATE_LEFT);
- }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index ad13efb..e462706 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -48,7 +48,6 @@
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.GestureState;
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.RecentsAnimationDeviceState;
@@ -127,9 +126,7 @@
void resetTaskViews() {
mFakeHotseatView.setVisibility(View.INVISIBLE);
mFakeIconView.setVisibility(View.INVISIBLE);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFakeIconView.getBackground().setTint(getFakeTaskViewColor());
- }
+ mFakeIconView.getBackground().setTint(getFakeTaskViewColor());
if (mTutorialFragment.getActivity() != null) {
int height = mTutorialFragment.getRootView().getFullscreenHeight();
int width = mTutorialFragment.getRootView().getWidth();
@@ -138,9 +135,7 @@
mFakeTaskViewRadius = 0;
mFakeTaskView.invalidateOutline();
mFakeTaskView.setVisibility(View.VISIBLE);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
- }
+ mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
mFakeTaskView.setAlpha(1);
mFakePreviousTaskView.setVisibility(View.INVISIBLE);
mFakePreviousTaskView.setAlpha(1);
@@ -390,12 +385,10 @@
false, /* isOpening */
mFakeIconView, mDp);
mFakeIconView.setAlpha(1);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- int iconColor = ColorUtils.blendARGB(
- getFakeTaskViewColor(), getHotseatIconColor(), progress);
- mFakeIconView.getBackground().setTint(iconColor);
- mFakeTaskView.setBackgroundColor(iconColor);
- }
+ int iconColor = ColorUtils.blendARGB(
+ getFakeTaskViewColor(), getHotseatIconColor(), progress);
+ mFakeIconView.getBackground().setTint(iconColor);
+ mFakeTaskView.setBackgroundColor(iconColor);
mFakeTaskView.setAlpha(getWindowAlpha(progress));
mFakePreviousTaskView.setAlpha(getWindowAlpha(progress));
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 54653fa..5028da4 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -19,10 +19,7 @@
import static android.view.View.NO_ID;
import static android.view.View.inflate;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -33,7 +30,6 @@
import android.graphics.Matrix;
import android.graphics.Outline;
import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.Log;
@@ -52,7 +48,6 @@
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.LayoutRes;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
@@ -153,8 +148,7 @@
mFakeHotseatView = rootView.findViewById(R.id.gesture_tutorial_fake_hotseat_view);
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
- mFakeTaskbarView = ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? null : rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view);
+ mFakeTaskbarView = null;
mFakePreviousTaskView =
rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
@@ -165,32 +159,30 @@
mFingerDotView = rootView.findViewById(R.id.gesture_tutorial_finger_dot);
mSkipTutorialDialog = createSkipTutorialDialog();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFullGestureDemonstration = rootView.findViewById(R.id.full_gesture_demonstration);
- mCheckmarkAnimation = rootView.findViewById(R.id.checkmark_animation);
- mAnimatedGestureDemonstration = rootView.findViewById(
- R.id.gesture_demonstration_animations);
- mExitingAppView = rootView.findViewById(R.id.exiting_app_back);
- mScreenWidth = mTutorialFragment.getDeviceProfile().widthPx;
- mScreenHeight = mTutorialFragment.getDeviceProfile().heightPx;
- mExitingAppMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.gesture_tutorial_back_gesture_exiting_app_margin);
- mExitingAppStartingCornerRadius = QuickStepContract.getWindowCornerRadius(mContext);
- mExitingAppEndingCornerRadius = mContext.getResources().getDimensionPixelSize(
- R.dimen.gesture_tutorial_back_gesture_end_corner_radius);
- mAnimatedGestureDemonstration.addLottieOnCompositionLoadedListener(
- this::createScalingMatrix);
+ mFullGestureDemonstration = rootView.findViewById(R.id.full_gesture_demonstration);
+ mCheckmarkAnimation = rootView.findViewById(R.id.checkmark_animation);
+ mAnimatedGestureDemonstration = rootView.findViewById(
+ R.id.gesture_demonstration_animations);
+ mExitingAppView = rootView.findViewById(R.id.exiting_app_back);
+ mScreenWidth = mTutorialFragment.getDeviceProfile().widthPx;
+ mScreenHeight = mTutorialFragment.getDeviceProfile().heightPx;
+ mExitingAppMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.gesture_tutorial_back_gesture_exiting_app_margin);
+ mExitingAppStartingCornerRadius = QuickStepContract.getWindowCornerRadius(mContext);
+ mExitingAppEndingCornerRadius = mContext.getResources().getDimensionPixelSize(
+ R.dimen.gesture_tutorial_back_gesture_end_corner_radius);
+ mAnimatedGestureDemonstration.addLottieOnCompositionLoadedListener(
+ this::createScalingMatrix);
- mFeedbackTitleView.setText(getIntroductionTitle());
- mFeedbackSubtitleView.setText(getIntroductionSubtitle());
- mExitingAppView.setClipToOutline(true);
- mExitingAppView.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(mExitingAppRect, mExitingAppRadius);
- }
- });
- }
+ mFeedbackTitleView.setText(getIntroductionTitle());
+ mFeedbackSubtitleView.setText(getIntroductionSubtitle());
+ mExitingAppView.setClipToOutline(true);
+ mExitingAppView.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(mExitingAppRect, mExitingAppRadius);
+ }
+ });
mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
AccessibilityEvent.TYPE_VIEW_FOCUSED);
@@ -261,19 +253,11 @@
@LayoutRes
protected int getMockHotseatResId() {
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- return mTutorialFragment.isLargeScreen()
- ? mTutorialFragment.isFoldable()
- ? R.layout.redesigned_gesture_tutorial_foldable_mock_hotseat
- : R.layout.redesigned_gesture_tutorial_tablet_mock_hotseat
- : R.layout.redesigned_gesture_tutorial_mock_hotseat;
- } else {
- return mTutorialFragment.isLargeScreen()
- ? mTutorialFragment.isFoldable()
- ? R.layout.gesture_tutorial_foldable_mock_hotseat
- : R.layout.gesture_tutorial_tablet_mock_hotseat
- : R.layout.gesture_tutorial_mock_hotseat;
- }
+ return mTutorialFragment.isLargeScreen()
+ ? mTutorialFragment.isFoldable()
+ ? R.layout.redesigned_gesture_tutorial_foldable_mock_hotseat
+ : R.layout.redesigned_gesture_tutorial_tablet_mock_hotseat
+ : R.layout.redesigned_gesture_tutorial_mock_hotseat;
}
@LayoutRes
@@ -312,9 +296,7 @@
@DrawableRes
public int getMockAppIconResId() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.drawable.redesigned_hotseat_icon
- : R.drawable.default_sandbox_app_icon;
+ return R.drawable.redesigned_hotseat_icon;
}
@DrawableRes
@@ -374,11 +356,7 @@
mFeedbackView.setTranslationY(0);
return;
}
- Animator gestureAnimation = mTutorialFragment.getGestureAnimation();
- AnimatedVectorDrawable edgeAnimation = mTutorialFragment.getEdgeAnimation();
- if (gestureAnimation != null && edgeAnimation != null) {
- playFeedbackAnimation(gestureAnimation, edgeAnimation, mShowFeedbackRunnable, true);
- }
+ playFeedbackAnimation();
}
/**
@@ -442,12 +420,7 @@
}
mFeedbackTitleView.setText(titleResId);
- mFeedbackSubtitleView.setText(
- ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() || spokenSubtitleResId == NO_ID
- ? mContext.getText(subtitleResId)
- : Utilities.wrapForTts(
- mContext.getText(subtitleResId),
- mContext.getString(spokenSubtitleResId)));
+ mFeedbackSubtitleView.setText(subtitleResId);
if (isGestureSuccessful) {
if (mTutorialFragment.isAtFinalStep()) {
showActionButton();
@@ -458,27 +431,16 @@
mFakeTaskViewCallback = null;
}
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- showSuccessPage();
- }
+ showSuccessPage();
}
mGestureCompleted = isGestureSuccessful;
-
- Animator gestureAnimation = mTutorialFragment.getGestureAnimation();
- AnimatedVectorDrawable edgeAnimation = mTutorialFragment.getEdgeAnimation();
- if (!isGestureSuccessful && gestureAnimation != null && edgeAnimation != null) {
- playFeedbackAnimation(
- gestureAnimation,
- edgeAnimation,
- mShowFeedbackRunnable,
- useGestureAnimationDelay);
- return;
+ if (!isGestureSuccessful) {
+ playFeedbackAnimation();
} else {
mTutorialFragment.releaseFeedbackAnimation();
+ mFeedbackViewCallback = mShowFeedbackRunnable;
+ mFeedbackView.post(mFeedbackViewCallback);
}
- mFeedbackViewCallback = mShowFeedbackRunnable;
-
- mFeedbackView.post(mFeedbackViewCallback);
}
private void showSuccessPage() {
@@ -517,79 +479,17 @@
mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
}
- private void playFeedbackAnimation(
- @NonNull Animator gestureAnimation,
- @NonNull AnimatedVectorDrawable edgeAnimation,
- @NonNull Runnable onStartRunnable,
- boolean useGestureAnimationDelay) {
-
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFeedbackView.setVisibility(View.VISIBLE);
- mAnimatedGestureDemonstration.setVisibility(View.VISIBLE);
- mFullGestureDemonstration.setVisibility(View.VISIBLE);
- mAnimatedGestureDemonstration.playAnimation();
- return;
- }
-
- if (gestureAnimation.isRunning()) {
- gestureAnimation.cancel();
- }
- if (edgeAnimation.isRunning()) {
- edgeAnimation.reset();
- }
- gestureAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
-
- mEdgeGestureVideoView.setVisibility(GONE);
- if (edgeAnimation.isRunning()) {
- edgeAnimation.stop();
- }
-
- if (!useGestureAnimationDelay) {
- onStartRunnable.run();
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
-
- mEdgeGestureVideoView.setVisibility(View.VISIBLE);
- edgeAnimation.start();
-
- gestureAnimation.removeListener(this);
- }
- });
-
- cancelQueuedGestureAnimation();
- if (useGestureAnimationDelay) {
- mFeedbackViewCallback = onStartRunnable;
- mFakeTaskViewCallback = gestureAnimation::start;
-
- mFeedbackView.post(mFeedbackViewCallback);
- mFakeTaskView.postDelayed(mFakeTaskViewCallback, GESTURE_ANIMATION_DELAY_MS);
- } else {
- gestureAnimation.start();
- }
+ private void playFeedbackAnimation() {
+ mFeedbackView.setVisibility(View.VISIBLE);
+ mAnimatedGestureDemonstration.setVisibility(View.VISIBLE);
+ mFullGestureDemonstration.setVisibility(View.VISIBLE);
+ mAnimatedGestureDemonstration.playAnimation();
}
void setRippleHotspot(float x, float y) {
mRippleDrawable.setHotspot(x, y);
}
- void showRippleEffect(@Nullable Runnable onCompleteRunnable) {
- mRippleDrawable.setState(
- new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled});
- mRippleView.postDelayed(() -> {
- mRippleDrawable.setState(new int[] {});
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- }, RIPPLE_VISIBLE_MS);
- }
-
void onActionButtonClicked(View button) {
mTutorialFragment.continueTutorial();
}
@@ -601,24 +501,19 @@
updateDrawables();
updateLayout();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFeedbackTitleView.setTextAppearance(mContext, getTitleTextAppearance());
- mDoneButton.setTextAppearance(mContext, getDoneButtonTextAppearance());
- mDoneButton.getBackground().setTint(getDoneButtonColor());
- mCheckmarkAnimation.setAnimation(mTutorialFragment.isAtFinalStep()
- ? R.raw.checkmark_animation_end
- : R.raw.checkmark_animation_in_progress);
- if (!isGestureCompleted()) {
- mCheckmarkAnimation.setVisibility(GONE);
- startGestureAnimation();
- if (mTutorialType == TutorialType.BACK_NAVIGATION) {
- resetViewsForBackGesture();
- }
-
+ mFeedbackTitleView.setTextAppearance(mContext, getTitleTextAppearance());
+ mDoneButton.setTextAppearance(mContext, getDoneButtonTextAppearance());
+ mDoneButton.getBackground().setTint(getDoneButtonColor());
+ mCheckmarkAnimation.setAnimation(mTutorialFragment.isAtFinalStep()
+ ? R.raw.checkmark_animation_end
+ : R.raw.checkmark_animation_in_progress);
+ if (!isGestureCompleted()) {
+ mCheckmarkAnimation.setVisibility(GONE);
+ startGestureAnimation();
+ if (mTutorialType == TutorialType.BACK_NAVIGATION) {
+ resetViewsForBackGesture();
}
- } else {
- hideFeedback();
- hideActionButton();
+
}
mGestureCompleted = false;
@@ -654,13 +549,6 @@
: R.style.TextAppearance_GestureTutorial_Feedback_Subtext_Dark);
}
- void hideActionButton() {
- mSkipButton.setVisibility(View.VISIBLE);
- // Invisible to maintain the layout.
- mDoneButton.setVisibility(View.INVISIBLE);
- mDoneButton.setOnClickListener(null);
- }
-
void showActionButton() {
mSkipButton.setVisibility(GONE);
mDoneButton.setVisibility(View.VISIBLE);
@@ -711,10 +599,8 @@
}
private void updateSubtext() {
- if (!ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mTutorialStepView.setTutorialProgress(
- mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps());
- }
+ mTutorialStepView.setTutorialProgress(
+ mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps());
}
private void updateHotseatChildViewColor(@Nullable View child) {
@@ -727,9 +613,7 @@
mTutorialFragment.getRootView().setBackground(AppCompatResources.getDrawable(
mContext, getMockWallpaperResId()));
mTutorialFragment.updateFeedbackAnimation();
- mFakeLauncherView.setBackgroundColor(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? getFakeLauncherColor()
- : mContext.getColor(R.color.gesture_tutorial_fake_wallpaper_color));
+ mFakeLauncherView.setBackgroundColor(getFakeLauncherColor());
updateFakeViewLayout(mFakeHotseatView, getMockHotseatResId());
mHotseatIconView = mFakeHotseatView.findViewById(R.id.hotseat_icon_1);
mFakeTaskView.animate().alpha(1).setListener(
@@ -738,19 +622,15 @@
mFakeIconView.setBackground(AppCompatResources.getDrawable(
mContext, getMockAppIconResId()));
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mExitingAppView.setBackgroundColor(getExitingAppColor());
- mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
- updateHotseatChildViewColor(mHotseatIconView);
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_6));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
- } else {
- updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
- }
+ mExitingAppView.setBackgroundColor(getExitingAppColor());
+ mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
+ updateHotseatChildViewColor(mHotseatIconView);
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_6));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 0fafb94..2ff2c83 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -17,7 +17,6 @@
import static android.view.View.NO_ID;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_GESTURE_COMPLETE;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_TUTORIAL_TYPE;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_USE_TUTORIAL_MENU;
@@ -215,9 +214,7 @@
super.onCreateView(inflater, container, savedInstanceState);
mRootView = (RootSandboxLayout) inflater.inflate(
- ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.redesigned_gesture_tutorial_fragment
- : R.layout.gesture_tutorial_fragment,
+ R.layout.redesigned_gesture_tutorial_fragment,
container,
false);
@@ -383,10 +380,7 @@
if (mTutorialController != null && !isGestureComplete()) {
mTutorialController.hideFeedback();
}
-
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mTutorialController.pauseAndHideLottieAnimation();
- }
+ mTutorialController.pauseAndHideLottieAnimation();
// Note: Using logical-or to ensure both functions get called.
return mEdgeBackGestureHandler.onTouch(view, motionEvent)
diff --git a/quickstep/src/com/android/quickstep/logging/LoggingModule.java b/quickstep/src/com/android/quickstep/logging/LoggingModule.java
new file mode 100644
index 0000000..8fdf3c7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/logging/LoggingModule.java
@@ -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.quickstep.logging;
+
+import android.content.Context;
+
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public class LoggingModule {
+ @Provides
+ @LauncherAppSingleton
+ SettingsChangeLogger provideSettingsChangeLogger(@ApplicationContext Context context) {
+ return SettingsChangeLogger.INSTANCE.get(context);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
index ec04cb7..658975c 100644
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -37,6 +37,7 @@
import androidx.annotation.VisibleForTesting
import androidx.core.util.component1
import androidx.core.util.component2
+import androidx.core.view.updateLayoutParams
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Flags
import com.android.launcher3.LauncherAnimUtils
@@ -242,7 +243,30 @@
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT
}
- override fun getDwbLayoutTranslations(
+ override fun updateDwbBannerLayout(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ isGroupedTaskView: Boolean,
+ deviceProfile: DeviceProfile,
+ snapshotViewWidth: Int,
+ snapshotViewHeight: Int,
+ banner: View
+ ) {
+ banner.pivotX = 0f
+ banner.pivotY = 0f
+ banner.rotation = degreesRotated
+ banner.updateLayoutParams<FrameLayout.LayoutParams> {
+ gravity = Gravity.TOP or if (banner.isLayoutRtl) Gravity.END else Gravity.START
+ width =
+ if (isGroupedTaskView) {
+ snapshotViewHeight
+ } else {
+ taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
+ }
+ }
+ }
+
+ override fun getDwbBannerTranslations(
taskViewWidth: Int,
taskViewHeight: Int,
splitBounds: SplitBounds?,
@@ -252,39 +276,25 @@
banner: View
): Pair<Float, Float> {
val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
- val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
val translationX = banner.height.toFloat()
-
- val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
- bannerParams.gravity = Gravity.TOP or if (isRtl) Gravity.END else Gravity.START
- banner.pivotX = 0f
- banner.pivotY = 0f
- banner.rotation = degreesRotated
-
- if (splitBounds == null) {
- // Single, fullscreen case
- bannerParams.width = taskViewHeight - snapshotParams.topMargin
- return Pair(translationX, snapshotParams.topMargin.toFloat())
- }
-
- // Set correct width and translations
val translationY: Float
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].measuredHeight
+ if (splitBounds == null) {
translationY = snapshotParams.topMargin.toFloat()
} else {
- bannerParams.width = thumbnailViews[1].measuredHeight
- val topLeftTaskPlusDividerPercent =
- if (splitBounds.appsStackedVertically) {
- splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
- } else {
- splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
- }
- translationY =
- snapshotParams.topMargin +
- (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ translationY = snapshotParams.topMargin.toFloat()
+ } else {
+ val topLeftTaskPlusDividerPercent =
+ if (splitBounds.appsStackedVertically) {
+ splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
+ } else {
+ splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
+ }
+ translationY =
+ snapshotParams.topMargin +
+ (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+ }
}
-
return Pair(translationX, translationY)
}
@@ -300,6 +310,7 @@
if (isRtl) displacement < 0 else displacement > 0
override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) 1 else -1
+
/* -------------------- */
override fun getChildBounds(
diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index eeacee1..cc022b2 100644
--- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -243,54 +243,54 @@
}
@Override
- public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
- int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
- View[] thumbnailViews, int desiredTaskId, View banner) {
- float translationX = 0;
- float translationY = 0;
+ public void updateDwbBannerLayout(int taskViewWidth, int taskViewHeight,
+ boolean isGroupedTaskView, @NonNull DeviceProfile deviceProfile,
+ int snapshotViewWidth, int snapshotViewHeight, @NonNull View banner) {
FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
banner.setPivotX(0);
banner.setPivotY(0);
banner.setRotation(getDegreesRotated());
- if (splitBounds == null) {
- // Single, fullscreen case
+ if (isGroupedTaskView) {
+ bannerParams.gravity =
+ BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL);
+ bannerParams.width = snapshotViewWidth;
+ } else {
bannerParams.width = MATCH_PARENT;
bannerParams.gravity = BOTTOM | CENTER_HORIZONTAL;
- return new Pair<>(translationX, translationY);
}
+ banner.setLayoutParams(bannerParams);
+ }
- bannerParams.gravity =
- BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL);
-
- // Set correct width
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].getMeasuredWidth();
- } else {
- bannerParams.width = thumbnailViews[1].getMeasuredWidth();
- }
-
- // Set translations
- if (deviceProfile.isLeftRightSplit) {
- if (desiredTaskId == splitBounds.rightBottomTaskId) {
- float leftTopTaskPercent = splitBounds.appsStackedVertically
- ? splitBounds.topTaskPercent
- : splitBounds.leftTaskPercent;
- float dividerThicknessPercent = splitBounds.appsStackedVertically
- ? splitBounds.dividerHeightPercent
- : splitBounds.dividerWidthPercent;
- translationX = ((taskViewWidth * leftTopTaskPercent)
- + (taskViewWidth * dividerThicknessPercent));
- }
- } else {
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- FrameLayout.LayoutParams snapshotParams =
- (FrameLayout.LayoutParams) thumbnailViews[0]
- .getLayoutParams();
- float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
- ? (1f - splitBounds.topTaskPercent)
- : (1f - splitBounds.leftTaskPercent);
- translationY = -((taskViewHeight - snapshotParams.topMargin)
- * bottomRightTaskPlusDividerPercent);
+ @NonNull
+ @Override
+ public Pair<Float, Float> getDwbBannerTranslations(int taskViewWidth,
+ int taskViewHeight, SplitBounds splitBounds, @NonNull DeviceProfile deviceProfile,
+ @NonNull View[] thumbnailViews, int desiredTaskId, @NonNull View banner) {
+ float translationX = 0;
+ float translationY = 0;
+ if (splitBounds != null) {
+ if (deviceProfile.isLeftRightSplit) {
+ if (desiredTaskId == splitBounds.rightBottomTaskId) {
+ float leftTopTaskPercent = splitBounds.appsStackedVertically
+ ? splitBounds.topTaskPercent
+ : splitBounds.leftTaskPercent;
+ float dividerThicknessPercent = splitBounds.appsStackedVertically
+ ? splitBounds.dividerHeightPercent
+ : splitBounds.dividerWidthPercent;
+ translationX = ((taskViewWidth * leftTopTaskPercent)
+ + (taskViewWidth * dividerThicknessPercent));
+ }
+ } else {
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ FrameLayout.LayoutParams snapshotParams =
+ (FrameLayout.LayoutParams) thumbnailViews[0]
+ .getLayoutParams();
+ float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
+ ? (1f - splitBounds.topTaskPercent)
+ : (1f - splitBounds.leftTaskPercent);
+ translationY = -((taskViewHeight - snapshotParams.topMargin)
+ * bottomRightTaskPlusDividerPercent);
+ }
}
}
return new Pair<>(translationX, translationY);
@@ -535,6 +535,18 @@
int parentWidth, int parentHeight, SplitBounds splitBoundsConfig,
DeviceProfile dp, boolean isRtl) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
+
+ FrameLayout.LayoutParams primaryParams =
+ (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
+ FrameLayout.LayoutParams secondaryParams =
+ (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
+
+ // Reset margin and translations that aren't used in this method, but are used in other
+ // `RecentsPagedOrientationHandler` variants.
+ secondaryParams.topMargin = 0;
+ primaryParams.topMargin = spaceAboveSnapshot;
+ primarySnapshot.setTranslationY(0);
+
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
float dividerScale = splitBoundsConfig.appsStackedVertically
? splitBoundsConfig.dividerHeightPercent
@@ -552,24 +564,14 @@
secondarySnapshot.setTranslationX(translationX);
primarySnapshot.setTranslationX(0);
}
- secondarySnapshot.setTranslationY(spaceAboveSnapshot);
- // Reset unused translations
- primarySnapshot.setTranslationY(0);
+ secondarySnapshot.setTranslationY(spaceAboveSnapshot);
} else {
float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
float translationY = taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight;
secondarySnapshot.setTranslationY(translationY);
- FrameLayout.LayoutParams primaryParams =
- (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
- FrameLayout.LayoutParams secondaryParams =
- (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
- secondaryParams.topMargin = 0;
- primaryParams.topMargin = spaceAboveSnapshot;
-
- // Reset unused translations
- primarySnapshot.setTranslationY(0);
+ // Reset unused translations.
secondarySnapshot.setTranslationX(0);
primarySnapshot.setTranslationX(0);
}
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
index df4b030..06a0685 100644
--- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -199,6 +199,7 @@
parentWidth: Int,
parentHeight: Int
): Pair<Point, Point>
+
// Overview TaskMenuView methods
/** Sets layout params on a task's app icon. Only use this when app chip is disabled. */
fun setTaskIconParams(
@@ -294,13 +295,24 @@
deviceProfile: DeviceProfile
)
+ /** Layout a Digital Wellbeing Banner on its parent. TaskView. */
+ fun updateDwbBannerLayout(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ isGroupedTaskView: Boolean,
+ deviceProfile: DeviceProfile,
+ snapshotViewWidth: Int,
+ snapshotViewHeight: Int,
+ banner: View
+ )
+
/**
- * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
+ * Calculates the translations where a Digital Wellbeing Banner should be apply on its parent
* TaskView.
*
* @return A Pair of Floats representing the proper x and y translations.
*/
- fun getDwbLayoutTranslations(
+ fun getDwbBannerTranslations(
taskViewWidth: Int,
taskViewHeight: Int,
splitBounds: SplitConfigurationOptions.SplitBounds?,
@@ -309,6 +321,7 @@
desiredTaskId: Int,
banner: View
): Pair<Float, Float>
+
// The following are only used by TaskViewTouchHandler.
/** @return Either VERTICAL or HORIZONTAL. */
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
index 333359f..a972e8c 100644
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -28,6 +28,7 @@
import android.widget.FrameLayout
import androidx.core.util.component1
import androidx.core.util.component2
+import androidx.core.view.updateLayoutParams
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Flags
import com.android.launcher3.R
@@ -125,7 +126,30 @@
}
}
- override fun getDwbLayoutTranslations(
+ override fun updateDwbBannerLayout(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ isGroupedTaskView: Boolean,
+ deviceProfile: DeviceProfile,
+ snapshotViewWidth: Int,
+ snapshotViewHeight: Int,
+ banner: View
+ ) {
+ banner.pivotX = 0f
+ banner.pivotY = 0f
+ banner.rotation = degreesRotated
+ banner.updateLayoutParams<FrameLayout.LayoutParams> {
+ gravity = Gravity.BOTTOM or if (banner.isLayoutRtl) Gravity.END else Gravity.START
+ width =
+ if (isGroupedTaskView) {
+ snapshotViewHeight
+ } else {
+ taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
+ }
+ }
+ }
+
+ override fun getDwbBannerTranslations(
taskViewWidth: Int,
taskViewHeight: Int,
splitBounds: SplitBounds?,
@@ -135,39 +159,26 @@
banner: View
): Pair<Float, Float> {
val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
- val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
-
- val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
- bannerParams.gravity = Gravity.BOTTOM or if (isRtl) Gravity.END else Gravity.START
- banner.pivotX = 0f
- banner.pivotY = 0f
- banner.rotation = degreesRotated
-
val translationX: Float = (taskViewWidth - banner.height).toFloat()
- if (splitBounds == null) {
- // Single, fullscreen case
- bannerParams.width = taskViewHeight - snapshotParams.topMargin
- return Pair(translationX, banner.height.toFloat())
- }
-
- // Set correct width and translations
val translationY: Float
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].measuredHeight
- val bottomRightTaskPlusDividerPercent =
- if (splitBounds.appsStackedVertically) {
- 1f - splitBounds.topTaskPercent
- } else {
- 1f - splitBounds.leftTaskPercent
- }
- translationY =
- banner.height -
- (taskViewHeight - snapshotParams.topMargin) * bottomRightTaskPlusDividerPercent
- } else {
- bannerParams.width = thumbnailViews[1].measuredHeight
+ if (splitBounds == null) {
translationY = banner.height.toFloat()
+ } else {
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ val bottomRightTaskPlusDividerPercent =
+ if (splitBounds.appsStackedVertically) {
+ 1f - splitBounds.topTaskPercent
+ } else {
+ 1f - splitBounds.leftTaskPercent
+ }
+ translationY =
+ banner.height -
+ (taskViewHeight - snapshotParams.topMargin) *
+ bottomRightTaskPlusDividerPercent
+ } else {
+ translationY = banner.height.toFloat()
+ }
}
-
return Pair(translationX, translationY)
}
@@ -339,6 +350,7 @@
if (isRtl) displacement > 0 else displacement < 0
override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) -1 else 1
+
/* -------------------- */
override fun getSplitIconsPosition(
diff --git a/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt b/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt
new file mode 100644
index 0000000..df546ca
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.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.recents.data
+
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+
+/** Notifies added callbacks that high res state has changed */
+interface HighResLoadingStateNotifier {
+ /** Adds a callback for high res loading state */
+ fun addCallback(callback: HighResLoadingStateChangedCallback)
+
+ /** Removes a callback for high res loading state */
+ fun removeCallback(callback: HighResLoadingStateChangedCallback)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
index 4f7a541..9c4248c 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -41,10 +41,4 @@
* populated e.g. icons/thumbnails etc.
*/
fun setVisibleTasks(visibleTaskIdList: List<Int>)
-
- /**
- * 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 addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>)
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
index feed2fd..d2cb595 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
@@ -23,6 +23,4 @@
*/
data class RecentsDeviceProfile(
val isLargeScreen: Boolean,
- val widthPx: Int,
- val heightPx: Int,
)
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
index ce39ff1..c64453d 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
@@ -26,7 +26,5 @@
RecentsDeviceProfileRepository {
override fun getRecentsDeviceProfile() =
- with(container.deviceProfile) {
- RecentsDeviceProfile(isLargeScreen = isTablet, widthPx = widthPx, heightPx = heightPx)
- }
+ with(container.deviceProfile) { RecentsDeviceProfile(isLargeScreen = isTablet) }
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt
new file mode 100644
index 0000000..6e7789d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.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.recents.data
+
+import com.android.quickstep.util.TaskVisualsChangeListener
+
+/** Notifies added listeners that task visuals have changed */
+interface TaskVisualsChangeNotifier {
+ /** Adds a listener for visuals changes */
+ fun addThumbnailChangeListener(listener: TaskVisualsChangeListener)
+
+ /** Removes a listener for visuals changes */
+ fun removeThumbnailChangeListener(listener: TaskVisualsChangeListener)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
new file mode 100644
index 0000000..a141e89
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import android.os.UserHandle
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
+import com.android.quickstep.util.TaskVisualsChangeListener
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+
+/** Delegates the checking of task visuals (thumbnails, high res changes, icons) */
+interface TaskVisualsChangedDelegate :
+ TaskVisualsChangeListener, HighResLoadingStateChangedCallback {
+ /** Registers a callback for visuals relating to icons */
+ fun registerTaskIconChangedCallback(
+ taskKey: Task.TaskKey,
+ taskIconChangedCallback: TaskIconChangedCallback
+ )
+
+ /** Unregisters a callback for visuals relating to icons */
+ fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey)
+
+ /** Registers a callback for visuals relating to thumbnails */
+ fun registerTaskThumbnailChangedCallback(
+ taskKey: Task.TaskKey,
+ taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+ )
+
+ /** Unregisters a callback for visuals relating to thumbnails */
+ fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey)
+
+ /** A callback for task icon changes */
+ interface TaskIconChangedCallback {
+ /** Informs the listener that the task icon has changed */
+ fun onTaskIconChanged()
+ }
+
+ /** A callback for task thumbnail changes */
+ interface TaskThumbnailChangedCallback {
+ /** Informs the listener that the task thumbnail data has changed to [thumbnailData] */
+ fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?)
+
+ /** Informs the listener that the default resolution for loading thumbnails has changed */
+ fun onHighResLoadingStateChanged()
+ }
+}
+
+class TaskVisualsChangedDelegateImpl(
+ private val taskVisualsChangeNotifier: TaskVisualsChangeNotifier,
+ private val highResLoadingStateNotifier: HighResLoadingStateNotifier,
+) : TaskVisualsChangedDelegate {
+ private val taskIconChangedCallbacks =
+ mutableMapOf<Int, Pair<Task.TaskKey, TaskIconChangedCallback>>()
+ private val taskThumbnailChangedCallbacks =
+ mutableMapOf<Int, Pair<Task.TaskKey, TaskThumbnailChangedCallback>>()
+ private var isListening = false
+
+ @Synchronized
+ private fun onCallbackRegistered() {
+ if (isListening) return
+
+ taskVisualsChangeNotifier.addThumbnailChangeListener(this)
+ highResLoadingStateNotifier.addCallback(this)
+ isListening = true
+ }
+
+ @Synchronized
+ private fun onCallbackUnregistered() {
+ if (!isListening) return
+
+ if (taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size == 0) {
+ taskVisualsChangeNotifier.removeThumbnailChangeListener(this)
+ highResLoadingStateNotifier.removeCallback(this)
+ }
+
+ isListening = false
+ }
+
+ override fun onTaskIconChanged(taskId: Int) {
+ taskIconChangedCallbacks[taskId]?.let { (_, callback) -> callback.onTaskIconChanged() }
+ }
+
+ override fun onTaskIconChanged(pkg: String, user: UserHandle) {
+ taskIconChangedCallbacks.values
+ .filter { (taskKey, _) ->
+ pkg == taskKey.packageName && user.identifier == taskKey.userId
+ }
+ .forEach { (_, callback) -> callback.onTaskIconChanged() }
+ }
+
+ override fun onTaskThumbnailChanged(taskId: Int, thumbnailData: ThumbnailData?): Task? {
+ taskThumbnailChangedCallbacks[taskId]?.let { (_, callback) ->
+ callback.onTaskThumbnailChanged(thumbnailData)
+ }
+ return null
+ }
+
+ override fun onHighResLoadingStateChanged(enabled: Boolean) {
+ taskThumbnailChangedCallbacks.values.forEach { (_, callback) ->
+ callback.onHighResLoadingStateChanged()
+ }
+ }
+
+ override fun registerTaskIconChangedCallback(
+ taskKey: Task.TaskKey,
+ taskIconChangedCallback: TaskIconChangedCallback
+ ) {
+ taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback
+ onCallbackRegistered()
+ }
+
+ override fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey) {
+ taskIconChangedCallbacks.remove(taskKey.id)
+ onCallbackUnregistered()
+ }
+
+ override fun registerTaskThumbnailChangedCallback(
+ taskKey: Task.TaskKey,
+ taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+ ) {
+ taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback
+ onCallbackRegistered()
+ }
+
+ override fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey) {
+ taskThumbnailChangedCallbacks.remove(taskKey.id)
+ onCallbackUnregistered()
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 6acc940..eb3c2d1 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -17,162 +17,182 @@
package com.android.quickstep.recents.data
import android.graphics.drawable.Drawable
+import com.android.launcher3.util.coroutines.DispatcherProvider
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
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.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.callbackFlow
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.launch
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,
+ private val taskVisualsChangedDelegate: TaskVisualsChangedDelegate,
+ 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) {
+ tasks,
+ thumbnailQueryResults,
+ iconQueryResults ->
+ tasks.onEach { task ->
+ // Add retrieved thumbnails + remove unnecessary thumbnails (e.g. invisible)
+ task.thumbnail = 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()
- addOrUpdateThumbnailOverride(emptyMap())
- }
-
- override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
- this.thumbnailOverride.value =
- 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)
- }
- .distinctUntilChanged()
+ private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest = callbackFlow {
+ trySend(task.key.id to task.thumbnail)
+ trySend(task.key.id to getThumbnailFromDataSource(task))
- /**
- * 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 callback =
+ object : TaskThumbnailChangedCallback {
+ override fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?) {
+ trySend(task.key.id to thumbnailData)
+ }
+
+ override fun onHighResLoadingStateChanged() {
+ launch { trySend(task.key.id to getThumbnailFromDataSource(task)) }
+ }
}
- 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() }
- }
- }
+ taskVisualsChangedDelegate.registerTaskThumbnailChangedCallback(task.key, callback)
+ awaitClose { taskVisualsChangedDelegate.unregisterTaskThumbnailChangedCallback(task.key) }
}
- /** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
+ /** Flow wrapper for [TaskIconDataSource.getIconInBackground] api */
private fun getIconDataRequest(task: Task): IconDataRequest =
- flow {
- emit(task.key.id to task.getTaskIconQueryResponse())
- val iconDataResponse: TaskIconQueryResponse? =
- suspendCancellableCoroutine { continuation ->
- val cancellableTask =
- taskIconDataSource.getIconInBackground(task) {
- icon,
- contentDescription,
- title ->
- icon.constantState?.let {
- continuation.resume(
- TaskIconQueryResponse(
- it.newDrawable().mutate(),
- contentDescription,
- title
- )
- )
- }
- }
- continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ callbackFlow {
+ trySend(task.key.id to task.getTaskIconQueryResponse())
+ trySend(task.key.id to getIconFromDataSource(task))
+
+ val callback =
+ object : TaskIconChangedCallback {
+ override fun onTaskIconChanged() {
+ launch { trySend(task.key.id to getIconFromDataSource(task)) }
+ }
}
- emit(task.key.id to iconDataResponse)
+ taskVisualsChangedDelegate.registerTaskIconChangedCallback(task.key, callback)
+ awaitClose {
+ taskVisualsChangedDelegate.unregisterTaskIconChangedCallback(task.key)
+ }
}
.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() }
+ private suspend fun getThumbnailFromDataSource(task: Task) =
+ withContext(dispatcherProvider.main) {
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskThumbnailDataSource.getThumbnailInBackground(task) {
+ continuation.resume(it)
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
}
}
- }
+
+ private suspend fun getIconFromDataSource(task: Task) =
+ 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() }
+ }
+ }
}
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..0a5544f 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -19,14 +19,16 @@
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.TaskVisualsChangedDelegate
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegateImpl
import com.android.quickstep.recents.data.TasksRepository
import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
import com.android.quickstep.recents.usecase.GetThumbnailUseCase
import com.android.quickstep.recents.usecase.SysUiStatusNavFlagsUseCase
import com.android.quickstep.recents.viewmodel.RecentsViewData
-import com.android.quickstep.task.thumbnail.GetSplashSizeUseCase
import com.android.quickstep.task.thumbnail.SplashAlphaUseCase
import com.android.quickstep.task.thumbnail.TaskThumbnailViewData
import com.android.quickstep.task.viewmodel.TaskContainerData
@@ -36,6 +38,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 +59,28 @@
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)
+ val recentsModel = RecentsModel.INSTANCE.get(appContext)
+ val taskVisualsChangedDelegate =
+ TaskVisualsChangedDelegateImpl(
+ recentsModel,
+ recentsModel.thumbnailCache.highResLoadingState
+ )
+ set(TaskVisualsChangedDelegate::class.java.simpleName, taskVisualsChangedDelegate)
// Create RecentsTaskRepository singleton
val recentTasksRepository: RecentTasksRepository =
- with(RecentsModel.INSTANCE.get(appContext)) {
- TasksRepository(this, thumbnailCache, iconCache)
+ with(recentsModel) {
+ TasksRepository(
+ this,
+ thumbnailCache,
+ iconCache,
+ taskVisualsChangedDelegate,
+ recentsCoroutineScope,
+ ProductionDispatchers
+ )
}
set(RecentTasksRepository::class.java.simpleName, recentTasksRepository)
}
@@ -137,7 +160,14 @@
when (modelClass) {
RecentTasksRepository::class.java -> {
with(RecentsModel.INSTANCE.get(appContext)) {
- TasksRepository(this, thumbnailCache, iconCache)
+ TasksRepository(
+ this,
+ thumbnailCache,
+ iconCache,
+ get(),
+ get(),
+ ProductionDispatchers
+ )
}
}
RecentsViewData::class.java -> RecentsViewData()
@@ -156,7 +186,6 @@
getThumbnailPositionUseCase = inject(),
tasksRepository = inject(),
splashAlphaUseCase = inject(scopeId),
- getSplashSizeUseCase = inject(scopeId),
)
TaskOverlayViewModel::class.java -> {
val task = extras["Task"] as Task
@@ -184,12 +213,6 @@
tasksRepository = inject(),
rotationStateRepository = inject(),
)
- GetSplashSizeUseCase::class.java ->
- GetSplashSizeUseCase(
- taskThumbnailViewData = inject(scopeId),
- taskViewData = inject(scopeId, extras),
- deviceProfileRepository = inject(),
- )
else -> {
log("Factory for ${modelClass.simpleName} not defined!", Log.ERROR)
error("Factory for ${modelClass.simpleName} not defined!")
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
index b1f46a3..1716f2e 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
@@ -58,10 +58,6 @@
recentsViewData.thumbnailSplashProgress.value = taskThumbnailSplashAlpha
}
- fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
- recentsTasksRepository.addOrUpdateThumbnailOverride(thumbnailOverride)
- }
-
suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>) {
combine(
updatedThumbnails.map {
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCase.kt b/quickstep/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCase.kt
deleted file mode 100644
index 145957a..0000000
--- a/quickstep/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCase.kt
+++ /dev/null
@@ -1,46 +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.quickstep.task.thumbnail
-
-import android.graphics.Point
-import android.graphics.drawable.Drawable
-import com.android.quickstep.recents.data.RecentsDeviceProfileRepository
-import com.android.quickstep.task.viewmodel.TaskViewData
-import kotlin.math.min
-
-class GetSplashSizeUseCase(
- private val taskThumbnailViewData: TaskThumbnailViewData,
- private val taskViewData: TaskViewData,
- private val deviceProfileRepository: RecentsDeviceProfileRepository,
-) {
- fun execute(splashImage: Drawable): Point {
- val recentsDeviceProfile = deviceProfileRepository.getRecentsDeviceProfile()
- val screenWidth = recentsDeviceProfile.widthPx
- val screenHeight = recentsDeviceProfile.heightPx
- val scaleAtFullscreen =
- min(
- screenWidth / taskThumbnailViewData.width.value,
- screenHeight / taskThumbnailViewData.height.value,
- )
- val scaleFactor: Float = 1f / taskViewData.nonGridScale.value / scaleAtFullscreen
- return Point(
- (splashImage.intrinsicWidth * scaleFactor / taskThumbnailViewData.scaleX.value).toInt(),
- (splashImage.intrinsicHeight * scaleFactor / taskThumbnailViewData.scaleY.value)
- .toInt(),
- )
- }
-}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
index a6be9f6..36a86f2 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
@@ -17,7 +17,6 @@
package com.android.quickstep.task.thumbnail
import android.graphics.Bitmap
-import android.graphics.Point
import android.graphics.drawable.Drawable
import android.view.Surface
import androidx.annotation.ColorInt
@@ -31,7 +30,7 @@
data class SnapshotSplash(
val snapshot: Snapshot,
- val splash: Splash,
+ val splash: Drawable?,
) : TaskThumbnailUiState()
data class Snapshot(
@@ -39,9 +38,4 @@
@Surface.Rotation val thumbnailRotation: Int,
@ColorInt val backgroundColor: Int
)
-
- data class Splash(
- val icon: Drawable?,
- val size: Point,
- )
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 41aee52..0279818 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -24,11 +24,9 @@
import android.util.AttributeSet
import android.view.View
import android.view.ViewOutlineProvider
-import android.widget.FrameLayout
-import android.widget.ImageView
import androidx.annotation.ColorInt
-import androidx.core.view.isVisible
-import androidx.core.view.updateLayoutParams
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.isInvisible
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.util.ViewPool
@@ -41,6 +39,7 @@
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
import com.android.quickstep.util.TaskCornerRadius
+import com.android.quickstep.views.FixedSizeImageView
import com.android.systemui.shared.system.QuickStepContract
import kotlin.math.abs
import kotlinx.coroutines.CoroutineName
@@ -51,7 +50,7 @@
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
+class TaskThumbnailView : ConstraintLayout, ViewPool.Reusable {
private val viewData: TaskThumbnailViewData by RecentsDependencies.inject(this)
private val viewModel: TaskThumbnailViewModel by RecentsDependencies.inject(this)
@@ -60,9 +59,9 @@
private val scrimView: View by lazy { findViewById(R.id.task_thumbnail_scrim) }
private val liveTileView: LiveTileView by lazy { findViewById(R.id.task_thumbnail_live_tile) }
- private val thumbnailView: ImageView by lazy { findViewById(R.id.task_thumbnail) }
- private val splashContainer: FrameLayout by lazy { findViewById(R.id.splash_container) }
- private val splashIcon: ImageView by lazy { findViewById(R.id.splash_icon) }
+ private val thumbnailView: FixedSizeImageView by lazy { findViewById(R.id.task_thumbnail) }
+ private val splashBackground: View by lazy { findViewById(R.id.splash_background) }
+ private val splashIcon: FixedSizeImageView by lazy { findViewById(R.id.splash_icon) }
private var uiState: TaskThumbnailUiState = Uninitialized
private var inheritedScale: Float = 1f
@@ -107,7 +106,10 @@
.onEach { dimProgress -> scrimView.alpha = dimProgress }
.launchIn(viewAttachedScope)
viewModel.splashAlpha
- .onEach { splashAlpha -> splashContainer.alpha = splashAlpha }
+ .onEach { splashAlpha ->
+ splashBackground.alpha = splashAlpha
+ splashIcon.alpha = splashAlpha
+ }
.launchIn(viewAttachedScope)
viewModel.cornerRadiusProgress.onEach { invalidateOutline() }.launchIn(viewAttachedScope)
viewModel.inheritedScale
@@ -152,15 +154,13 @@
override fun setScaleX(scaleX: Float) {
super.setScaleX(scaleX)
- viewData.scaleX.value = scaleX
- // Splash icon should ignore scale
+ // Splash icon should ignore scale on TTV
splashIcon.scaleX = 1 / scaleX
}
override fun setScaleY(scaleY: Float) {
super.setScaleY(scaleY)
- viewData.scaleY.value = scaleY
- // Splash icon should ignore scale
+ // Splash icon should ignore scale on TTV
splashIcon.scaleY = 1 / scaleY
}
@@ -173,9 +173,10 @@
}
private fun resetViews() {
- liveTileView.isVisible = false
- thumbnailView.isVisible = false
- splashContainer.alpha = 0f
+ liveTileView.isInvisible = true
+ thumbnailView.isInvisible = true
+ splashBackground.alpha = 0f
+ splashIcon.alpha = 0f
scrimView.alpha = 0f
setBackgroundColor(Color.BLACK)
}
@@ -185,25 +186,20 @@
}
private fun drawLiveWindow() {
- liveTileView.isVisible = true
+ liveTileView.isInvisible = false
}
private fun drawSnapshotSplash(snapshotSplash: SnapshotSplash) {
drawSnapshot(snapshotSplash.snapshot)
- splashContainer.isVisible = true
- splashContainer.setBackgroundColor(snapshotSplash.snapshot.backgroundColor)
- splashIcon.setImageDrawable(snapshotSplash.splash.icon)
- splashIcon.updateLayoutParams<LayoutParams> {
- width = snapshotSplash.splash.size.x
- height = snapshotSplash.splash.size.y
- }
+ splashBackground.setBackgroundColor(snapshotSplash.snapshot.backgroundColor)
+ splashIcon.setImageDrawable(snapshotSplash.splash)
}
private fun drawSnapshot(snapshot: Snapshot) {
drawBackground(snapshot.backgroundColor)
thumbnailView.setImageBitmap(snapshot.bitmap)
- thumbnailView.isVisible = true
+ thumbnailView.isInvisible = false
setImageMatrix()
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt
index 1f8c0bc..3502029 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewData.kt
@@ -21,6 +21,4 @@
class TaskThumbnailViewData {
val width = MutableStateFlow(0)
val height = MutableStateFlow(0)
- val scaleX = MutableStateFlow(1f)
- val scaleY = MutableStateFlow(1f)
}
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
index 4e29840..b1bb65e 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
@@ -19,20 +19,17 @@
import android.annotation.ColorInt
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.graphics.Matrix
-import android.graphics.Point
import androidx.core.graphics.ColorUtils
import com.android.quickstep.recents.data.RecentTasksRepository
import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
import com.android.quickstep.recents.usecase.ThumbnailPositionState
import com.android.quickstep.recents.viewmodel.RecentsViewData
-import com.android.quickstep.task.thumbnail.GetSplashSizeUseCase
import com.android.quickstep.task.thumbnail.SplashAlphaUseCase
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.SnapshotSplash
-import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Splash
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.systemui.shared.recents.model.Task
import kotlin.math.max
@@ -55,7 +52,6 @@
private val tasksRepository: RecentTasksRepository,
private val getThumbnailPositionUseCase: GetThumbnailPositionUseCase,
private val splashAlphaUseCase: SplashAlphaUseCase,
- private val getSplashSizeUseCase: GetSplashSizeUseCase,
) {
private val task = MutableStateFlow<Flow<Task?>>(flowOf(null))
private val splashProgress = MutableStateFlow(flowOf(0f))
@@ -100,7 +96,7 @@
isBackgroundOnly(taskVal) ->
BackgroundOnly(taskVal.colorBackground.removeAlpha())
isSnapshotSplashState(taskVal) ->
- SnapshotSplash(createSnapshotState(taskVal), createSplashState(taskVal))
+ SnapshotSplash(createSnapshotState(taskVal), taskVal.icon)
else -> Uninitialized
}
}
@@ -139,12 +135,6 @@
return Snapshot(bitmap, thumbnailData.rotation, task.colorBackground.removeAlpha())
}
- private fun createSplashState(task: Task): Splash {
- val taskIcon = task.icon
- val size = if (taskIcon == null) Point() else getSplashSizeUseCase.execute(taskIcon)
- return Splash(taskIcon, size)
- }
-
@ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
private companion object {
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
index 07dfc29..7a9ecf2 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
@@ -23,8 +23,6 @@
// This is typically a View concern but it is used to invalidate rendering in other Views
val scale = MutableStateFlow(1f)
- val nonGridScale = MutableStateFlow(1f)
-
// TODO(b/331753115): This property should not be in TaskViewData once TaskView is MVVM.
/** Whether outline of TaskView is formed by outline thumbnail view(s). */
val isOutlineFormedByThumbnailView: Boolean = taskViewType != TaskViewType.DESKTOP
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
index 30ee360..ec75d59 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewModel.kt
@@ -22,8 +22,4 @@
fun updateScale(scale: Float) {
taskViewData.scale.value = scale
}
-
- fun updateNonGridScale(nonGridScale: Float) {
- taskViewData.nonGridScale.value = nonGridScale
- }
}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index c54862a..d46b8fc 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -23,6 +23,7 @@
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -237,7 +238,8 @@
/** An entire log of entries associated with a single log ID */
protected static class EventLog {
- protected final List<EventEntry> eventEntries = new ArrayList<>();
+ protected final List<EventEntry> eventEntries =
+ Collections.synchronizedList(new ArrayList<>());
protected final int logId;
protected final boolean mIsFullyGesturalNavMode;
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index c7c04ed..b583a4b 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -21,7 +21,6 @@
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
-import android.animation.AnimatorSet;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Matrix;
@@ -34,18 +33,11 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.touch.AllAppsSwipeController;
-import com.android.quickstep.DeviceConfigWrapper;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.RecentsViewContainer;
/**
* Controls an animation that can go beyond progress = 1, at which point resistance should be
@@ -57,10 +49,8 @@
private enum RecentsResistanceParams {
FROM_APP(0.75f, 0.5f, 1f, false),
- FROM_APP_TO_ALL_APPS(1f, 0.6f, 0.8f, false),
FROM_APP_TABLET(1f, 0.7f, 1f, true),
FROM_APP_TABLET_GRID_ONLY(1f, 1f, 1f, true),
- FROM_APP_TO_ALL_APPS_TABLET(1f, 0.5f, 0.5f, false),
FROM_OVERVIEW(1f, 0.75f, 0.5f, false);
RecentsResistanceParams(float scaleStartResist, float scaleMaxResist,
@@ -157,46 +147,10 @@
RecentsParams params = new RecentsParams(context, recentsOrientedState, dp, scaleTarget,
scaleProperty, translationTarget, translationProperty);
PendingAnimation resistAnim = createRecentsResistanceAnim(params);
-
- // Apply All Apps animation during the resistance animation.
- if (recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()) {
- RecentsViewContainer container =
- recentsOrientedState.getContainerInterface().getCreatedContainer();
- if (container != null) {
- RecentsView recentsView = container.getOverviewPanel();
- StateManager<LauncherState, StatefulActivity<LauncherState>> stateManager =
- recentsView.getStateManager();
- if (stateManager.isInStableState(LauncherState.BACKGROUND_APP)
- && stateManager.isInTransition()) {
-
- // Calculate the resistance progress threshold where All Apps will trigger.
- float threshold = getAllAppsThreshold(context, recentsOrientedState, dp);
-
- StateAnimationConfig config = new StateAnimationConfig();
- AllAppsSwipeController.applyOverviewToAllAppsAnimConfig(dp, config, threshold);
- AnimatorSet allAppsAnimator = stateManager.createAnimationToNewWorkspace(
- LauncherState.ALL_APPS, config).getTarget();
- resistAnim.add(allAppsAnimator);
- }
- }
- }
-
AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
return new AnimatorControllerWithResistance(normalController, resistanceController);
}
- private static float getAllAppsThreshold(Context context,
- RecentsOrientedState recentsOrientedState, DeviceProfile dp) {
- int transitionDragLength =
- recentsOrientedState.getContainerInterface().getSwipeUpDestinationAndLength(
- dp, context, TEMP_RECT,
- recentsOrientedState.getOrientationHandler());
- float dragLengthFactor = (float) dp.heightPx / transitionDragLength;
- // -1s are because 0-1 is reserved for the normal transition.
- float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f;
- return (threshold - 1) / (dragLengthFactor - 1);
- }
-
/**
* Creates the resistance animation for {@link #createForRecents}, or can be used separately
* when starting from recents, i.e. {@link #createRecentsResistanceFromOverviewAnim}.
@@ -305,17 +259,11 @@
this.translationTarget = translationTarget;
this.translationProperty = translationProperty;
if (dp.isTablet) {
- resistanceParams =
- recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()
- ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS_TABLET
- : enableGridOnlyOverview()
- ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY
- : RecentsResistanceParams.FROM_APP_TABLET;
+ resistanceParams = enableGridOnlyOverview()
+ ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY
+ : RecentsResistanceParams.FROM_APP_TABLET;
} else {
- resistanceParams =
- recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()
- ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS
- : RecentsResistanceParams.FROM_APP;
+ resistanceParams = RecentsResistanceParams.FROM_APP;
}
}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index c3d74bb..e1013db 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -26,11 +26,11 @@
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_NONE;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.isPersistentSnapPosition;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_NONE;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.isPersistentSnapPosition;
import android.content.Context;
import android.content.Intent;
@@ -70,10 +70,11 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
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,14 +233,16 @@
*
* @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);
ComponentKey app2Key = new ComponentKey(app2.getTargetComponent(), app2.user);
- mSplitSelectStateController.setLaunchingCuj(cuj);
- InteractionJankMonitorWrapper.begin(appPairIcon, cuj);
+ mSplitSelectStateController.setLaunchingCuj(appPairIcon, cuj);
mSplitSelectStateController.findLastActiveTasksAndRunCallback(
Arrays.asList(app1Key, app2Key),
@@ -273,12 +276,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/BackAnimState.kt b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
new file mode 100644
index 0000000..9009eaa
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.animation.AnimatorSet
+import android.content.Context
+import com.android.launcher3.LauncherAnimationRunner.AnimationResult
+import com.android.launcher3.anim.AnimatorListeners.forEndCallback
+import com.android.launcher3.util.RunnableList
+
+/** Interface to represent animation for back to Launcher transition */
+interface BackAnimState {
+
+ fun addOnAnimCompleteCallback(r: Runnable)
+
+ fun applyToAnimationResult(result: AnimationResult, c: Context)
+
+ fun start()
+}
+
+class AnimatorBackState(private val springAnim: RectFSpringAnim?, private val anim: AnimatorSet?) :
+ BackAnimState {
+
+ override fun addOnAnimCompleteCallback(r: Runnable) {
+ val springAnimWait = RunnableList()
+ springAnim?.addAnimatorListener(forEndCallback(springAnimWait::executeAllAndDestroy))
+ ?: springAnimWait.executeAllAndDestroy()
+
+ val animWait = RunnableList()
+ anim?.addListener(
+ forEndCallback(Runnable { springAnimWait.add(animWait::executeAllAndDestroy) })
+ ) ?: springAnimWait.add(animWait::executeAllAndDestroy)
+ animWait.add(r)
+ }
+
+ override fun applyToAnimationResult(result: AnimationResult, c: Context) {
+ result.setAnimation(anim, c)
+ }
+
+ override fun start() {
+ anim?.start()
+ }
+}
+
+class AlreadyStartedBackAnimState(private val onEndCallback: RunnableList) : BackAnimState {
+
+ override fun addOnAnimCompleteCallback(r: Runnable) {
+ onEndCallback.add(r)
+ }
+
+ override fun applyToAnimationResult(result: AnimationResult, c: Context) {
+ addOnAnimCompleteCallback(result::onAnimationFinished)
+ }
+
+ override fun start() {}
+}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index 26668c8..4c26761 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -31,7 +31,6 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.HorizontalInsettableView;
import com.android.quickstep.SystemUiProxy;
@@ -80,17 +79,12 @@
@UnfoldMain RotationChangeProvider rotationChangeProvider) {
mLauncher = launcher;
- if (FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) {
- mPreemptiveProgressProvider = new PreemptiveUnfoldTransitionProgressProvider(
- unfoldTransitionProgressProvider, launcher.getMainThreadHandler());
- mPreemptiveProgressProvider.init();
+ mPreemptiveProgressProvider = new PreemptiveUnfoldTransitionProgressProvider(
+ unfoldTransitionProgressProvider, launcher.getMainThreadHandler());
+ mPreemptiveProgressProvider.init();
- mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
- mPreemptiveProgressProvider);
- } else {
- mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
- unfoldTransitionProgressProvider);
- }
+ mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
+ mPreemptiveProgressProvider);
unfoldTransitionProgressProvider.addCallback(mExternalTransitionStatusProvider);
unfoldTransitionProgressProvider.addCallback(
@@ -169,10 +163,6 @@
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
- if (!FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) {
- return;
- }
-
if (mIsTablet != null && dp.isTablet != mIsTablet) {
// We should preemptively start the animation only if:
// - We changed to the unfolded screen
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ec1eeb1..a8460c9 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -23,11 +23,13 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
-import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
public class LayoutUtils {
+ private static final float SQUARE_ASPECT_RATIO_TOLERANCE = 0.05f;
+
/**
* The height for the swipe up motion
*/
@@ -39,11 +41,14 @@
return swipeHeight;
}
- public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
- RecentsPagedOrientationHandler orientationHandler) {
+ public static int getShelfTrackingDistance(
+ Context context,
+ DeviceProfile dp,
+ RecentsPagedOrientationHandler orientationHandler,
+ BaseContainerInterface<?, ?> baseContainerInterface) {
// Track the bottom of the window.
Rect taskSize = new Rect();
- LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
+ baseContainerInterface.calculateTaskSize(context, dp, taskSize,
orientationHandler);
return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
}
@@ -61,4 +66,13 @@
}
}
}
+
+ /**
+ * Returns true iff the device's aspect ratio is within
+ * {@link LayoutUtils#SQUARE_ASPECT_RATIO_TOLERANCE} of 1:1
+ */
+ public static boolean isAspectRatioSquare(float aspectRatio) {
+ return Float.compare(aspectRatio, 1f - SQUARE_ASPECT_RATIO_TOLERANCE) >= 0
+ && Float.compare(aspectRatio, 1f + SQUARE_ASPECT_RATIO_TOLERANCE) <= 0;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
index 0b05c2e..63fe017 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
+import static com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -33,8 +34,10 @@
public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0;
public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
+ public static final int INDEX_RECENTS_ATTACHED_ALPHA_ANIM =
+ AtomicAnimationFactory.NEXT_INDEX + 2;
- private static final int MY_ANIM_COUNT = 2;
+ private static final int MY_ANIM_COUNT = 3;
protected final CONTAINER mContainer;
@@ -50,6 +53,7 @@
ObjectAnimator alpha = ObjectAnimator.ofFloat(mContainer.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
return alpha;
+ case INDEX_RECENTS_ATTACHED_ALPHA_ANIM:
case INDEX_RECENTS_TRANSLATE_X_ANIM: {
RecentsView rv = mContainer.getOverviewPanel();
return new SpringAnimationBuilder(mContainer)
@@ -57,7 +61,8 @@
.setDampingRatio(0.8f)
.setStiffness(250)
.setValues(values)
- .build(rv, ADJACENT_PAGE_HORIZONTAL_OFFSET);
+ .build(rv, index == INDEX_RECENTS_ATTACHED_ALPHA_ANIM
+ ? RUNNING_TASK_ATTACH_ALPHA : ADJACENT_PAGE_HORIZONTAL_OFFSET);
}
default:
return super.createStateElementAnimation(index, values);
diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
new file mode 100644
index 0000000..595aa00
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
+import com.android.quickstep.RecentsAnimationController
+import com.android.quickstep.views.DesktopTaskView
+import com.android.quickstep.views.TaskView
+import com.android.quickstep.views.TaskViewType
+import com.android.systemui.shared.recents.model.ThumbnailData
+
+/**
+ * Helper class for [com.android.quickstep.views.RecentsView]. This util class contains refactored
+ * and extracted functions from RecentsView to facilitate the implementation of unit tests.
+ */
+class RecentsViewUtils {
+
+ /**
+ * Sort task groups to move desktop tasks to the end of the list.
+ *
+ * @param tasks List of group tasks to be sorted.
+ * @return Sorted list of GroupTasks to be used in the RecentsView.
+ */
+ fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> {
+ val (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP }
+ return otherTasks + desktopTasks
+ }
+
+ fun getFocusedTaskIndex(taskGroups: List<GroupTask>): Int {
+ // The focused task index is placed after the desktop tasks views.
+ return if (enableLargeDesktopWindowingTile()) {
+ taskGroups.count { it.taskViewType == TaskViewType.DESKTOP }
+ } else {
+ 0
+ }
+ }
+
+ /**
+ * Counts [TaskView]s that are [DesktopTaskView] instances.
+ *
+ * @param taskViews List of [TaskView]s
+ */
+ fun getDesktopTaskViewCount(taskViews: List<TaskView>): Int =
+ taskViews.count { it is DesktopTaskView }
+
+ /** Returns a list of all large TaskView Ids from [TaskView]s */
+ fun getLargeTaskViewIds(taskViews: Iterable<TaskView>): List<Int> =
+ taskViews.filter { it.isLargeTile }.map { it.taskViewId }
+
+ /**
+ * Returns the first TaskView that should be displayed as a large tile.
+ *
+ * @param taskViews List of [TaskView]s
+ */
+ fun getFirstLargeTaskView(taskViews: List<TaskView>): TaskView? =
+ taskViews.firstOrNull { it.isLargeTile }
+
+ fun screenshotTasks(
+ taskView: TaskView,
+ recentsAnimationController: RecentsAnimationController,
+ ): Map<Int, ThumbnailData> =
+ taskView.taskContainers.associate {
+ it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
+ }
+
+ /** Returns the current list of [TaskView] children. */
+ fun getTaskViews(taskViewCount: Int, requireTaskViewAt: (Int) -> TaskView): List<TaskView> =
+ (0 until taskViewCount).map(requireTaskViewAt)
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 0335fa1..256e29e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -91,7 +91,8 @@
val iconDrawable: Drawable,
val fadeWithThumbnail: Boolean,
val isStagedTask: Boolean,
- val iconView: View?
+ val iconView: View?,
+ val contentDescription: CharSequence?
)
}
@@ -112,7 +113,8 @@
splitSelectSource.drawable,
fadeWithThumbnail = false,
isStagedTask = true,
- iconView = null
+ iconView = null,
+ splitSelectSource.itemInfo.contentDescription
)
} else if (splitSelectStateController.isDismissingFromSplitPair) {
// Initiating split from overview, but on a split pair
@@ -126,7 +128,8 @@
drawable,
fadeWithThumbnail = true,
isStagedTask = true,
- iconView = container.iconView.asView()
+ iconView = container.iconView.asView(),
+ container.task.titleDescription
)
}
}
@@ -145,7 +148,8 @@
drawable,
fadeWithThumbnail = true,
isStagedTask = true,
- iconView = it.iconView.asView()
+ iconView = it.iconView.asView(),
+ it.task.titleDescription
)
}
}
@@ -727,16 +731,19 @@
val mainRootCandidate = splitRoots.first
// Will contain changes (1) and (2) in diagram above
val leafRoots: List<Change> = splitRoots.second
+ // Don't rely on DP.isLeftRightSplit because if launcher is portrait apps could still
+ // launch in landscape if system auto-rotate is enabled and phone is held horizontally
+ val isLeftRightSplit = leafRoots.all { it.endAbsBounds.top == 0 }
// Find the place where our left/top app window meets the divider (used for the
// launcher side animation)
val leftTopApp =
leafRoots.single { change ->
- (dp.isLeftRightSplit && change.endAbsBounds.left == 0) ||
- (!dp.isLeftRightSplit && change.endAbsBounds.top == 0)
+ (isLeftRightSplit && change.endAbsBounds.left == 0) ||
+ (!isLeftRightSplit && change.endAbsBounds.top == 0)
}
val dividerPos =
- if (dp.isLeftRightSplit) leftTopApp.endAbsBounds.right
+ if (isLeftRightSplit) leftTopApp.endAbsBounds.right
else leftTopApp.endAbsBounds.bottom
// Create a new floating view in Launcher, positioned above the launching icon
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
index d58cb91..d982e81 100644
--- a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
@@ -17,14 +17,13 @@
package com.android.quickstep.util
import android.util.Log
-import android.view.WindowManager
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.TransitionInfo.Change
import android.window.TransitionInfo.FLAG_FIRST_CUSTOM
import com.android.launcher3.util.SplitConfigurationOptions
-import com.android.wm.shell.util.SplitBounds
+import com.android.wm.shell.shared.split.SplitBounds
import java.lang.IllegalStateException
class SplitScreenUtils {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 54f2dd3..1af12f1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -34,8 +34,8 @@
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_PENDINGINTENT;
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
-import static com.android.wm.shell.common.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -55,11 +55,11 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceControl;
+import android.view.View;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.RemoteTransition;
import android.window.RemoteTransitionStub;
@@ -97,10 +97,9 @@
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.SplitInstructionsView;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.splitscreen.ISplitSelectListener;
import java.io.PrintWriter;
@@ -150,9 +149,10 @@
/**
* Should be a constant from {@link com.android.internal.jank.Cuj} or -1, does not need to be
- * set for all launches.
+ * set for all launches. Used in conjunction with {@link #mLaunchingViewCuj} below.
*/
private int mLaunchCuj = -1;
+ private View mLaunchingViewCuj;
private FloatingTaskView mFirstFloatingTaskView;
private SplitInstructionsView mSplitInstructionsView;
@@ -652,7 +652,12 @@
return mSplitAnimationController;
}
- public void setLaunchingCuj(int launchCuj) {
+ /**
+ * Set params to invoke a trace session for the given view and CUJ when we begin animating the
+ * split launch AFTER we get a response from Shell.
+ */
+ public void setLaunchingCuj(View launchingView, int launchCuj) {
+ mLaunchingViewCuj = launchingView;
mLaunchCuj = launchCuj;
}
@@ -690,6 +695,9 @@
&& mLaunchingTaskView.getRecentsView() != null
&& mLaunchingTaskView.getRecentsView().isTaskViewVisible(
mLaunchingTaskView);
+ if (mLaunchingViewCuj != null && mLaunchCuj != -1) {
+ InteractionJankMonitorWrapper.begin(mLaunchingViewCuj, mLaunchCuj);
+ }
mSplitAnimationController.playSplitLaunchAnimation(
shouldLaunchFromTaskView ? mLaunchingTaskView : null,
mLaunchingIconView,
@@ -752,6 +760,7 @@
InteractionJankMonitorWrapper.end(mLaunchCuj);
}
mLaunchCuj = -1;
+ mLaunchingViewCuj = null;
if (mSessionInstanceIds != null) {
mStatsLogManager.logger()
@@ -836,7 +845,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,
@@ -847,21 +856,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;
}
@@ -884,20 +886,22 @@
Log.w(TAG, "Package not found: " + packageName, e);
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
- SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
- false /* allowMinimizeSplitScreen */);
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
DesktopSplitRecentsAnimationListener listener =
new DesktopSplitRecentsAnimationListener(splitPosition, taskBounds);
- MAIN_EXECUTOR.execute(() -> {
- callbacks.addListener(listener);
- UI_HELPER_EXECUTOR.execute(
- // Transition from app to enter stage split in launcher with
- // recents animation.
- () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
- mOverviewComponentObserver.getOverviewIntent(),
- SystemClock.uptimeMillis(), callbacks, null, null));
+ callbacks.addListener(listener);
+ UI_HELPER_EXECUTOR.execute(() -> {
+ // Transition from app to enter stage split in launcher with recents animation
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+ options.setTransientLaunch();
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext())
+ .startRecentsActivity(
+ mOverviewComponentObserver.getOverviewIntent(), options,
+ callbacks);
});
}
@@ -954,4 +958,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/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 27fb31d..4c6e4ff 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -27,9 +27,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.SystemClock;
import androidx.annotation.BinderThread;
@@ -84,19 +84,23 @@
return;
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
- SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
- false /* allowMinimizeSplitScreen */);
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
SplitWithKeyboardShortcutRecentsAnimationListener listener =
new SplitWithKeyboardShortcutRecentsAnimationListener(leftOrTop);
MAIN_EXECUTOR.execute(() -> {
callbacks.addListener(listener);
- UI_HELPER_EXECUTOR.execute(
- // Transition from fullscreen app to enter stage split in launcher with
- // recents animation.
- () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
- mOverviewComponentObserver.getOverviewIntent(),
- SystemClock.uptimeMillis(), callbacks, null, null));
+ UI_HELPER_EXECUTOR.execute(() -> {
+ // Transition from fullscreen app to enter stage split in launcher with
+ // recents animation
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+ options.setTransientLaunch();
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext())
+ .startRecentsActivity(mOverviewComponentObserver.getOverviewIntent(),
+ ActivityOptions.makeBasic(), callbacks);
+ });
});
}
@@ -110,17 +114,17 @@
private final boolean mLeftOrTop;
private final Rect mTempRect = new Rect();
+ private final ActivityManager.RunningTaskInfo mRunningTaskInfo;
private SplitWithKeyboardShortcutRecentsAnimationListener(boolean leftOrTop) {
mLeftOrTop = leftOrTop;
+ mRunningTaskInfo = ActivityManagerWrapper.getInstance().getRunningTask();
}
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
- ActivityManager.RunningTaskInfo runningTaskInfo =
- ActivityManagerWrapper.getInstance().getRunningTask();
- mController.setInitialTaskSelect(runningTaskInfo,
+ mController.setInitialTaskSelect(mRunningTaskInfo,
mLeftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT,
null /* itemInfo */,
mLeftOrTop ? LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP
@@ -136,9 +140,9 @@
RectF startingTaskRect = new RectF();
final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(
mLauncher, mLauncher.getDragLayer(),
- controller.screenshotTask(runningTaskInfo.taskId).getThumbnail(),
+ controller.screenshotTask(mRunningTaskInfo.taskId).getThumbnail(),
null /* icon */, startingTaskRect);
- Task task = Task.from(new Task.TaskKey(runningTaskInfo), runningTaskInfo,
+ Task task = Task.from(new Task.TaskKey(mRunningTaskInfo), mRunningTaskInfo,
false /* isLocked */);
RecentsModel.INSTANCE.get(mLauncher.getApplicationContext())
.getIconCache()
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 56e91ed..828322b 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -39,7 +39,7 @@
import com.android.quickstep.TaskAnimationManager;
import com.android.systemui.shared.pip.PipSurfaceTransactionHelper;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.pip.PipContentOverlay;
+import com.android.wm.shell.shared.pip.PipContentOverlay;
/**
* Subclass of {@link RectFSpringAnim} that animates an Activity to PiP (picture-in-picture) window
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 304b8f4..c3270dc 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -30,7 +30,6 @@
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
-import com.android.quickstep.LauncherActivityInterface;
import java.util.List;
import java.util.Set;
@@ -40,8 +39,17 @@
*/
public class SystemWindowManagerProxy extends WindowManagerProxy {
+ private final TISBindHelper mTISBindHelper;
+
public SystemWindowManagerProxy(Context context) {
super(true);
+ mTISBindHelper = new TISBindHelper(context, binder -> {});
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ mTISBindHelper.onDestroy();
}
@Override
@@ -53,7 +61,7 @@
@Override
public boolean isInDesktopMode() {
DesktopVisibilityController desktopController =
- LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ mTISBindHelper.getDesktopVisibilityController();
return desktopController != null && desktopController.areDesktopTasksVisible();
}
diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
index 9a01042..b573604 100644
--- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
@@ -25,6 +25,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.TaskbarManager;
import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.TouchInteractionService;
@@ -108,6 +109,11 @@
return mBinder == null ? null : mBinder.getTaskbarManager();
}
+ @Nullable
+ public DesktopVisibilityController getDesktopVisibilityController() {
+ return mBinder == null ? null : mBinder.getDesktopVisibilityController();
+ }
+
/**
* Sets flag whether a predictive back-to-home animation is in progress
*/
diff --git a/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java b/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java
index 98d363e..498078b 100644
--- a/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java
@@ -22,13 +22,13 @@
import com.android.launcher3.util.IntArray;
import java.lang.annotation.Retention;
+import java.util.List;
/**
* Helper class for navigating RecentsView grid tasks via arrow keys and tab.
*/
public class TaskGridNavHelper {
public static final int CLEAR_ALL_PLACEHOLDER_ID = -1;
- public static final int INVALID_FOCUSED_TASK_ID = -1;
public static final int DIRECTION_UP = 0;
public static final int DIRECTION_DOWN = 1;
@@ -43,25 +43,25 @@
private final IntArray mOriginalTopRowIds;
private IntArray mTopRowIds;
private IntArray mBottomRowIds;
- private final int mFocusedTaskId;
- public TaskGridNavHelper(IntArray topIds, IntArray bottomIds, int focusedTaskId) {
- mFocusedTaskId = focusedTaskId;
+ public TaskGridNavHelper(IntArray topIds, IntArray bottomIds,
+ List<Integer> largeTileIds) {
mOriginalTopRowIds = topIds.clone();
- generateTaskViewIdGrid(topIds, bottomIds);
+ generateTaskViewIdGrid(topIds, bottomIds, largeTileIds);
}
- private void generateTaskViewIdGrid(IntArray topRowIdArray, IntArray bottomRowIdArray) {
- boolean hasFocusedTask = mFocusedTaskId != INVALID_FOCUSED_TASK_ID;
- int maxSize =
- Math.max(topRowIdArray.size(), bottomRowIdArray.size()) + (hasFocusedTask ? 1 : 0);
- int minSize =
- Math.min(topRowIdArray.size(), bottomRowIdArray.size()) + (hasFocusedTask ? 1 : 0);
+ private void generateTaskViewIdGrid(IntArray topRowIdArray, IntArray bottomRowIdArray,
+ List<Integer> largeTileIds) {
- // Add the focused task to the beginning of both arrays if it exists.
- if (hasFocusedTask) {
- topRowIdArray.add(0, mFocusedTaskId);
- bottomRowIdArray.add(0, mFocusedTaskId);
+ int maxSize = Math.max(topRowIdArray.size(), bottomRowIdArray.size())
+ + largeTileIds.size();
+ int minSize = Math.min(topRowIdArray.size(), bottomRowIdArray.size())
+ + largeTileIds.size();
+
+ // Add Large tile task views first at the beginning
+ for (int i = 0; i < largeTileIds.size(); i++) {
+ topRowIdArray.add(i, largeTileIds.get(i));
+ bottomRowIdArray.add(i, largeTileIds.get(i));
}
// Fill in the shorter array with the ids from the longer one.
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index d9b7d20..c7777d8 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -24,7 +24,6 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
@@ -171,7 +170,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 +183,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 +493,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
@@ -525,21 +534,12 @@
// If mDrawsBelowRecents is unset, no reordering will be enforced.
if (mDrawsBelowRecents != null) {
- // In legacy transitions, the animation leashes remain in same hierarchy in the
- // TaskDisplayArea, so we don't want to bump the layer too high otherwise it will
- // conflict with layers that WM core positions (ie. the input consumers). For shell
- // transitions, the animation leashes are reparented to an animation container so we
- // can bump layers as needed.
- if (ENABLE_SHELL_TRANSITIONS) {
- builder.setLayer(mDrawsBelowRecents
- ? Integer.MIN_VALUE + app.prefixOrderIndex
- // 1000 is an arbitrary number to give room for multiple layers.
- : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
- } else {
- builder.setLayer(mDrawsBelowRecents
- ? Integer.MIN_VALUE + app.prefixOrderIndex
- : 0);
- }
+ // In shell transitions, the animation leashes are reparented to an animation container
+ // so we can bump layers as needed.
+ builder.setLayer(mDrawsBelowRecents
+ ? Integer.MIN_VALUE + app.prefixOrderIndex
+ // 1000 is an arbitrary number to give room for multiple layers.
+ : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java b/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
index 66bff73..519ef60 100644
--- a/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
+import android.annotation.NonNull;
import android.os.UserHandle;
import com.android.systemui.shared.recents.model.Task;
@@ -36,7 +37,7 @@
/**
* Called when the icon for a task changes
*/
- default void onTaskIconChanged(String pkg, UserHandle user) {}
+ default void onTaskIconChanged(@NonNull String pkg, @NonNull UserHandle user) {}
/**
* Called when the icon for a task changes
diff --git a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
index 09563f5..915c9e5 100644
--- a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
+++ b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
@@ -22,7 +22,6 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
import com.android.launcher3.anim.PendingAnimation
-import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.uioverrides.QuickstepLauncher
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
@@ -30,7 +29,7 @@
/** Controls animations that are happening during unfolding foldable devices */
class LauncherUnfoldTransitionController(
private val launcher: QuickstepLauncher,
- private val progressProvider: ProxyUnfoldTransitionProvider
+ private val progressProvider: ProxyUnfoldTransitionProvider,
) : OnDeviceProfileChangeListener, ActivityLifecycleCallbacksAdapter, TransitionProgressListener {
private var isTablet: Boolean? = null
@@ -57,10 +56,6 @@
}
override fun onDeviceProfileChanged(dp: DeviceProfile) {
- if (!FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) {
- return
- }
-
if (isTablet != null && dp.isTablet != isTablet) {
// We should preemptively start the animation only if:
// - We changed to the unfolded screen
@@ -93,7 +88,7 @@
provider = this,
factory = this::onPrepareUnfoldAnimation,
duration =
- 1000L // The expected duration for the animation. Then only comes to play if we have
+ 1000L, // The expected duration for the animation. Then only comes to play if we have
// to run the animation ourselves in case sysui misses the end signal
)
timeoutAlarm.cancelAlarm()
@@ -119,7 +114,7 @@
launcher,
isVertical,
dp.displayInfo.currentSize,
- anim
+ anim,
)
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 384945b..6db0923 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -15,18 +15,19 @@
*/
package com.android.quickstep.views
+import android.annotation.SuppressLint
import android.content.Context
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
import android.util.Log
+import android.view.Gravity
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
@@ -86,9 +87,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
}
@@ -119,11 +126,7 @@
snapshotView,
// Add snapshotView to the front after initial views e.g. icon and
// background.
- childCountAtInflation,
- LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
+ childCountAtInflation
)
TaskContainer(
this,
@@ -152,28 +155,37 @@
}
}
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- val containerWidth = MeasureSpec.getSize(widthMeasureSpec)
- var containerHeight = MeasureSpec.getSize(heightMeasureSpec)
- setMeasuredDimension(containerWidth, containerHeight)
-
+ @SuppressLint("RtlHardcoded")
+ override fun updateTaskSize(
+ lastComputedTaskSize: Rect,
+ lastComputedGridTaskSize: Rect,
+ lastComputedCarouselTaskSize: Rect
+ ) {
+ super.updateTaskSize(
+ lastComputedTaskSize,
+ lastComputedGridTaskSize,
+ lastComputedCarouselTaskSize
+ )
if (taskContainers.isEmpty()) {
return
}
val thumbnailTopMarginPx = container.deviceProfile.overviewTaskThumbnailTopMarginPx
- containerHeight -= thumbnailTopMarginPx
+
+ val containerWidth = layoutParams.width
+ val containerHeight = layoutParams.height - thumbnailTopMarginPx
BaseContainerInterface.getTaskDimension(mContext, container.deviceProfile, tempPointF)
+
val windowWidth = tempPointF.x.toInt()
val windowHeight = tempPointF.y.toInt()
val scaleWidth = containerWidth / windowWidth.toFloat()
val scaleHeight = containerHeight / windowHeight.toFloat()
+
if (DEBUG) {
Log.d(
TAG,
- "onMeasure: container=[$containerWidth,$containerHeight] " +
+ "onMeasure: container=[$containerWidth,$containerHeight]" +
"window=[$windowWidth,$windowHeight] scale=[$scaleWidth,$scaleHeight]"
)
}
@@ -189,27 +201,26 @@
right = windowWidth / 4
bottom = windowHeight / 4
}
- val thumbWidth = (taskSize.width() * scaleWidth).toInt()
- val thumbHeight = (taskSize.height() * scaleHeight).toInt()
- it.snapshotView.measure(
- MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY)
- )
+ val positionInParent = it.task.positionInParent ?: ORIGIN
// Position the task to the same position as it would be on the desktop
- val positionInParent = it.task.positionInParent ?: ORIGIN
- val taskX = (positionInParent.x * scaleWidth).toInt()
- var taskY = (positionInParent.y * scaleHeight).toInt()
- // move task down by margin size
- taskY += thumbnailTopMarginPx
- it.snapshotView.x = taskX.toFloat()
- it.snapshotView.y = taskY.toFloat()
+ it.snapshotView.updateLayoutParams<LayoutParams> {
+ gravity = Gravity.LEFT or Gravity.TOP
+ width = (taskSize.width() * scaleWidth).toInt()
+ height = (taskSize.height() * scaleHeight).toInt()
+ leftMargin = (positionInParent.x * scaleWidth).toInt()
+ topMargin =
+ (positionInParent.y * scaleHeight).toInt() +
+ container.deviceProfile.overviewTaskThumbnailTopMarginPx
+ }
if (DEBUG) {
- Log.d(
- TAG,
- "onMeasure: task=${it.task.key} thumb=[$thumbWidth,$thumbHeight]" +
- " pos=[$taskX,$taskY]"
- )
+ with(it.snapshotView.layoutParams as LayoutParams) {
+ Log.d(
+ TAG,
+ "onMeasure: task=${it.task.key} size=[$width,$height]" +
+ " margin=[$leftMargin,$topMargin]"
+ )
+ }
}
}
}
@@ -236,7 +247,7 @@
}
}
- override fun launchTaskAnimated(): RunnableList? {
+ private fun launchTaskWithDesktopController(animated: Boolean): RunnableList? {
val recentsView = recentsView ?: return null
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN,
@@ -246,18 +257,25 @@
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,
+ "launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated"
+ )
// Callbacks get run from recentsView for case when recents animation already running
recentsView.addSideTaskLaunchCallback(endCallback)
return endCallback
}
- override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
- launchTasks()
- callback(true)
- }
+ override fun launchAsStaticTile() = launchTaskWithDesktopController(animated = true)
+
+ override fun launchWithoutAnimation(
+ isQuickSwitch: Boolean,
+ callback: (launched: Boolean) -> Unit
+ ) = launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false)
// Desktop tile can't be in split screen
override fun confirmSecondSplitSelectApp(): Boolean = false
@@ -266,8 +284,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() {
@@ -281,6 +298,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/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
deleted file mode 100644
index 9f268a0..0000000
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.views;
-
-import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
-
-import static com.android.launcher3.Utilities.prefixTextWithIcon;
-import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
-
-import android.app.ActivityOptions;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.LauncherApps.AppUsageLimit;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.icu.text.MeasureFormat;
-import android.icu.text.MeasureFormat.FormatWidth;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Pair;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.quickstep.TaskUtils;
-import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
-import com.android.systemui.shared.recents.model.Task;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.time.Duration;
-import java.util.Locale;
-
-public final class DigitalWellBeingToast {
-
- private static final float THRESHOLD_LEFT_ICON_ONLY = 0.4f;
- private static final float THRESHOLD_RIGHT_ICON_ONLY = 0.6f;
-
- /** Will span entire width of taskView with full text */
- private static final int SPLIT_BANNER_FULLSCREEN = 0;
- /** Used for grid task view, only showing icon and time */
- private static final int SPLIT_GRID_BANNER_LARGE = 1;
- /** Used for grid task view, only showing icon */
- private static final int SPLIT_GRID_BANNER_SMALL = 2;
-
- @IntDef(value = {
- SPLIT_BANNER_FULLSCREEN,
- SPLIT_GRID_BANNER_LARGE,
- SPLIT_GRID_BANNER_SMALL,
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface SplitBannerConfig {
- }
-
- static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS);
- static final int MINUTE_MS = 60000;
-
- private static final String TAG = "DigitalWellBeingToast";
-
- private final RecentsViewContainer mContainer;
- private final TaskView mTaskView;
- private final LauncherApps mLauncherApps;
-
- private final int mBannerHeight;
-
- private Task mTask;
- private boolean mHasLimit;
-
- private long mAppRemainingTimeMs;
- @Nullable
- private View mBanner;
- private ViewOutlineProvider mOldBannerOutlineProvider;
- private float mBannerOffsetPercentage;
- @Nullable
- private SplitBounds mSplitBounds;
- private float mSplitOffsetTranslationY;
- private float mSplitOffsetTranslationX;
-
- private boolean mIsDestroyed = false;
-
- public DigitalWellBeingToast(RecentsViewContainer container, TaskView taskView) {
- mContainer = container;
- mTaskView = taskView;
- mLauncherApps = container.asContext().getSystemService(LauncherApps.class);
- mBannerHeight = container.asContext().getResources().getDimensionPixelSize(
- R.dimen.digital_wellbeing_toast_height);
- }
-
- private void setNoLimit() {
- mHasLimit = false;
- mTaskView.setContentDescription(mTask.titleDescription);
- replaceBanner(null);
- mAppRemainingTimeMs = -1;
- }
-
- private void setLimit(long appUsageLimitTimeMs, long appRemainingTimeMs) {
- mAppRemainingTimeMs = appRemainingTimeMs;
- mHasLimit = true;
- TextView toast = mContainer.getViewCache().getView(R.layout.digital_wellbeing_toast,
- mContainer.asContext(), mTaskView);
- toast.setText(prefixTextWithIcon(mContainer.asContext(), R.drawable.ic_hourglass_top,
- getText()));
- toast.setOnClickListener(this::openAppUsageSettings);
- replaceBanner(toast);
-
- mTaskView.setContentDescription(
- getContentDescriptionForTask(mTask, appUsageLimitTimeMs, appRemainingTimeMs));
- }
-
- public String getText() {
- return getText(mAppRemainingTimeMs, false /* forContentDesc */);
- }
-
- public boolean hasLimit() {
- return mHasLimit;
- }
-
- public void initialize(Task task) {
- if (mIsDestroyed) {
- throw new IllegalStateException("Cannot re-initialize a destroyed toast");
- }
- mTask = task;
- ORDERED_BG_EXECUTOR.execute(() -> {
- AppUsageLimit usageLimit = null;
- try {
- usageLimit = mLauncherApps.getAppUsageLimit(
- mTask.getTopComponent().getPackageName(),
- UserHandle.of(mTask.key.userId));
- } catch (Exception e) {
- Log.e(TAG, "Error initializing digital well being toast", e);
- }
- final long appUsageLimitTimeMs =
- usageLimit != null ? usageLimit.getTotalUsageLimit() : -1;
- final long appRemainingTimeMs =
- usageLimit != null ? usageLimit.getUsageRemaining() : -1;
-
- mTaskView.post(() -> {
- if (mIsDestroyed) {
- return;
- }
- if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
- setNoLimit();
- } else {
- setLimit(appUsageLimitTimeMs, appRemainingTimeMs);
- }
- });
- });
- }
-
- /**
- * Mark the DWB toast as destroyed and remove banner from TaskView.
- */
- public void destroy() {
- mIsDestroyed = true;
- mTaskView.post(() -> replaceBanner(null));
- }
-
- public void setSplitBounds(@Nullable SplitBounds splitBounds) {
- mSplitBounds = splitBounds;
- }
-
- private @SplitBannerConfig int getSplitBannerConfig() {
- if (mSplitBounds == null
- || !mContainer.getDeviceProfile().isTablet
- || mTaskView.isFocusedTask()) {
- return SPLIT_BANNER_FULLSCREEN;
- }
-
- // For portrait grid only height of task changes, not width. So we keep the text the same
- if (!mContainer.getDeviceProfile().isLeftRightSplit) {
- return SPLIT_GRID_BANNER_LARGE;
- }
-
- // For landscape grid, for 30% width we only show icon, otherwise show icon and time
- if (mTask.key.id == mSplitBounds.leftTopTaskId) {
- return mSplitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY
- ? SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
- } else {
- return mSplitBounds.leftTaskPercent > THRESHOLD_RIGHT_ICON_ONLY
- ? SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
- }
- }
-
- private String getReadableDuration(
- Duration duration,
- @StringRes int durationLessThanOneMinuteStringId) {
- int hours = Math.toIntExact(duration.toHours());
- int minutes = Math.toIntExact(duration.minusHours(hours).toMinutes());
-
- // Apply FormatWidth.WIDE if both the hour part and the minute part are non-zero.
- if (hours > 0 && minutes > 0) {
- return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.NARROW)
- .formatMeasures(
- new Measure(hours, MeasureUnit.HOUR),
- new Measure(minutes, MeasureUnit.MINUTE));
- }
-
- // Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
- if (hours > 0) {
- return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
- new Measure(hours, MeasureUnit.HOUR));
- }
-
- // Apply FormatWidth.WIDE if only the minute part is non-zero (unless forced).
- if (minutes > 0) {
- return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
- new Measure(minutes, MeasureUnit.MINUTE));
- }
-
- // Use a specific string for usage less than one minute but non-zero.
- if (duration.compareTo(Duration.ZERO) > 0) {
- return mContainer.asContext().getString(durationLessThanOneMinuteStringId);
- }
-
- // Otherwise, return 0-minute string.
- return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
- new Measure(0, MeasureUnit.MINUTE));
- }
-
- /**
- * Returns text to show for the banner depending on {@link #getSplitBannerConfig()}
- * If {@param forContentDesc} is {@code true}, this will always return the full
- * string corresponding to {@link #SPLIT_BANNER_FULLSCREEN}
- */
- private String getText(long remainingTime, boolean forContentDesc) {
- final Duration duration = Duration.ofMillis(
- remainingTime > MINUTE_MS ?
- (remainingTime + MINUTE_MS - 1) / MINUTE_MS * MINUTE_MS :
- remainingTime);
- String readableDuration = getReadableDuration(duration,
- R.string.shorter_duration_less_than_one_minute
- /* forceFormatWidth */);
- @SplitBannerConfig int splitBannerConfig = getSplitBannerConfig();
- if (forContentDesc || splitBannerConfig == SPLIT_BANNER_FULLSCREEN) {
- return mContainer.asContext().getString(
- R.string.time_left_for_app,
- readableDuration);
- }
-
- if (splitBannerConfig == SPLIT_GRID_BANNER_SMALL) {
- // show no text
- return "";
- } else { // SPLIT_GRID_BANNER_LARGE
- // only show time
- return readableDuration;
- }
- }
-
- public void openAppUsageSettings(View view) {
- final Intent intent = new Intent(OPEN_APP_USAGE_SETTINGS_TEMPLATE)
- .putExtra(Intent.EXTRA_PACKAGE_NAME,
- mTask.getTopComponent().getPackageName()).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- try {
- final RecentsViewContainer container =
- RecentsViewContainer.containerFromContext(view.getContext());
- final ActivityOptions options = ActivityOptions.makeScaleUpAnimation(
- view, 0, 0,
- view.getWidth(), view.getHeight());
- container.asContext().startActivity(intent, options.toBundle());
-
- // TODO: add WW logging on the app usage settings click.
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "Failed to open app usage settings for task "
- + mTask.getTopComponent().getPackageName(), e);
- }
- }
-
- private String getContentDescriptionForTask(
- Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) {
- return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ?
- mContainer.asContext().getString(
- R.string.task_contents_description_with_remaining_time,
- task.titleDescription,
- getText(appRemainingTimeMs, true /* forContentDesc */)) :
- task.titleDescription;
- }
-
- private void replaceBanner(@Nullable View view) {
- resetOldBanner();
- setBanner(view);
- }
-
- private void resetOldBanner() {
- if (mBanner != null) {
- mBanner.setOutlineProvider(mOldBannerOutlineProvider);
- mTaskView.removeView(mBanner);
- mBanner.setOnClickListener(null);
- mContainer.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner);
- }
- }
-
- private void setBanner(@Nullable View view) {
- mBanner = view;
- if (mBanner != null && mTaskView.getRecentsView() != null) {
- setupAndAddBanner();
- setBannerOutline();
- }
- }
-
- private void setupAndAddBanner() {
- FrameLayout.LayoutParams layoutParams =
- (FrameLayout.LayoutParams) mBanner.getLayoutParams();
- DeviceProfile deviceProfile = mContainer.getDeviceProfile();
- layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
- mTaskView.getFirstSnapshotView().getLayoutParams()).bottomMargin;
- RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
- Pair<Float, Float> translations = orientationHandler
- .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
- mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
- mTaskView.getSnapshotViews(), mTask.key.id, mBanner);
- mSplitOffsetTranslationX = translations.first;
- mSplitOffsetTranslationY = translations.second;
- updateTranslationY();
- updateTranslationX();
- mTaskView.addView(mBanner);
- }
-
- private void setBannerOutline() {
- // TODO(b\273367585) to investigate why mBanner.getOutlineProvider() can be null
- mOldBannerOutlineProvider = mBanner.getOutlineProvider() != null
- ? mBanner.getOutlineProvider()
- : ViewOutlineProvider.BACKGROUND;
-
- mBanner.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- mOldBannerOutlineProvider.getOutline(view, outline);
- float verticalTranslation = -view.getTranslationY() + mSplitOffsetTranslationY;
- outline.offset(0, Math.round(verticalTranslation));
- }
- });
- mBanner.setClipToOutline(true);
- }
-
- void updateBannerOffset(float offsetPercentage) {
- if (mBannerOffsetPercentage != offsetPercentage) {
- mBannerOffsetPercentage = offsetPercentage;
- if (mBanner != null) {
- updateTranslationY();
- mBanner.invalidateOutline();
- }
- }
- }
-
- private void updateTranslationY() {
- if (mBanner == null) {
- return;
- }
-
- mBanner.setTranslationY(
- (mBannerOffsetPercentage * mBannerHeight) + mSplitOffsetTranslationY);
- }
-
- private void updateTranslationX() {
- if (mBanner == null) {
- return;
- }
-
- mBanner.setTranslationX(mSplitOffsetTranslationX);
- }
-
- void setBannerColorTint(int color, float amount) {
- if (mBanner == null) {
- return;
- }
- if (amount == 0) {
- mBanner.setLayerType(View.LAYER_TYPE_NONE, null);
- }
- Paint layerPaint = new Paint();
- layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
- mBanner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint);
- mBanner.setLayerPaint(layerPaint);
- }
-
- void setBannerVisibility(int visibility) {
- if (mBanner == null) {
- return;
- }
-
- mBanner.setVisibility(visibility);
- }
-
- private int getAccessibilityActionId() {
- return (mSplitBounds != null
- && mSplitBounds.rightBottomTaskId == mTask.key.id)
- ? R.id.action_digital_wellbeing_bottom_right
- : R.id.action_digital_wellbeing_top_left;
- }
-
- @Nullable
- public AccessibilityNodeInfo.AccessibilityAction getDWBAccessibilityAction() {
- if (!hasLimit()) {
- return null;
- }
-
- Context context = mContainer.asContext();
- String label =
- (mTaskView.containsMultipleTasks())
- ? context.getString(
- R.string.split_app_usage_settings,
- TaskUtils.getTitle(context, mTask)
- ) : context.getString(R.string.accessibility_app_usage_settings);
- return new AccessibilityNodeInfo.AccessibilityAction(getAccessibilityActionId(), label);
- }
-
- public boolean handleAccessibilityAction(int action) {
- if (getAccessibilityActionId() == action) {
- openAppUsageSettings(mTaskView);
- return true;
- } else {
- return false;
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
new file mode 100644
index 0000000..7b97c23
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views
+
+import android.annotation.SuppressLint
+import android.app.ActivityOptions
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.LauncherApps.AppUsageLimit
+import android.graphics.Outline
+import android.graphics.Paint
+import android.icu.text.MeasureFormat
+import android.icu.util.Measure
+import android.icu.util.MeasureUnit
+import android.os.UserHandle
+import android.provider.Settings
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+import android.view.ViewOutlineProvider
+import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.TextView
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.component1
+import androidx.core.util.component2
+import androidx.core.view.isVisible
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.quickstep.TaskUtils
+import com.android.systemui.shared.recents.model.Task
+import java.time.Duration
+import java.util.Locale
+
+@SuppressLint("AppCompatCustomView")
+class DigitalWellBeingToast
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : TextView(context, attrs, defStyleAttr, defStyleRes) {
+ private val recentsViewContainer =
+ RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
+
+ private val launcherApps: LauncherApps? = context.getSystemService(LauncherApps::class.java)
+
+ private val bannerHeight =
+ context.resources.getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height)
+
+ private lateinit var task: Task
+ private lateinit var taskView: TaskView
+ private lateinit var snapshotView: View
+ @StagePosition private var stagePosition = STAGE_POSITION_UNDEFINED
+
+ private var appRemainingTimeMs: Long = 0
+ private var splitOffsetTranslationY = 0f
+ set(value) {
+ if (field != value) {
+ field = value
+ updateTranslationY()
+ }
+ }
+
+ private var isDestroyed = false
+
+ var hasLimit = false
+ var splitBounds: SplitConfigurationOptions.SplitBounds? = null
+ var bannerOffsetPercentage = 0f
+ set(value) {
+ if (field != value) {
+ field = value
+ updateTranslationY()
+ }
+ }
+
+ init {
+ setOnClickListener(::openAppUsageSettings)
+ outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View, outline: Outline) {
+ BACKGROUND.getOutline(view, outline)
+ val verticalTranslation = splitOffsetTranslationY - translationY
+ outline.offset(0, Math.round(verticalTranslation))
+ }
+ }
+ clipToOutline = true
+ }
+
+ private fun setNoLimit() {
+ isVisible = false
+ hasLimit = false
+ appRemainingTimeMs = -1
+ setContentDescription(appUsageLimitTimeMs = -1, appRemainingTimeMs = -1)
+ }
+
+ private fun setLimit(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) {
+ isVisible = true
+ hasLimit = true
+ this.appRemainingTimeMs = appRemainingTimeMs
+ setContentDescription(appUsageLimitTimeMs, appRemainingTimeMs)
+ text = Utilities.prefixTextWithIcon(context, R.drawable.ic_hourglass_top, getBannerText())
+ }
+
+ private fun setContentDescription(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) {
+ val contentDescription =
+ getContentDescriptionForTask(task, appUsageLimitTimeMs, appRemainingTimeMs)
+ snapshotView.contentDescription = contentDescription
+ }
+
+ fun initialize() {
+ check(!isDestroyed) { "Cannot re-initialize a destroyed toast" }
+ setupTranslations()
+ Executors.ORDERED_BG_EXECUTOR.execute {
+ var usageLimit: AppUsageLimit? = null
+ try {
+ usageLimit =
+ launcherApps?.getAppUsageLimit(
+ task.topComponent.packageName,
+ UserHandle.of(task.key.userId)
+ )
+ } catch (e: Exception) {
+ Log.e(TAG, "Error initializing digital well being toast", e)
+ }
+ val appUsageLimitTimeMs = usageLimit?.totalUsageLimit ?: -1
+ val appRemainingTimeMs = usageLimit?.usageRemaining ?: -1
+
+ taskView.post {
+ if (isDestroyed) return@post
+ if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
+ setNoLimit()
+ } else {
+ setLimit(appUsageLimitTimeMs, appRemainingTimeMs)
+ }
+ }
+ }
+ }
+
+ /** Bind the DWB toast to its dependencies. */
+ fun bind(
+ task: Task,
+ taskView: TaskView,
+ snapshotView: View,
+ @StagePosition stagePosition: Int
+ ) {
+ this.task = task
+ this.taskView = taskView
+ this.snapshotView = snapshotView
+ this.stagePosition = stagePosition
+ isDestroyed = false
+ }
+
+ /** Mark the DWB toast as destroyed and hide it. */
+ fun destroy() {
+ isVisible = false
+ isDestroyed = true
+ }
+
+ private fun getSplitBannerConfig(): SplitBannerConfig {
+ val splitBounds = splitBounds
+ return when {
+ splitBounds == null ||
+ !recentsViewContainer.deviceProfile.isTablet ||
+ taskView.isLargeTile -> SplitBannerConfig.SPLIT_BANNER_FULLSCREEN
+ // For portrait grid only height of task changes, not width. So we keep the text the
+ // same
+ !recentsViewContainer.deviceProfile.isLeftRightSplit ->
+ SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
+ // For landscape grid, for 30% width we only show icon, otherwise show icon and time
+ task.key.id == splitBounds.leftTopTaskId ->
+ if (splitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY)
+ SplitBannerConfig.SPLIT_GRID_BANNER_SMALL
+ else SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
+ else ->
+ if (splitBounds.leftTaskPercent > THRESHOLD_RIGHT_ICON_ONLY)
+ SplitBannerConfig.SPLIT_GRID_BANNER_SMALL
+ else SplitBannerConfig.SPLIT_GRID_BANNER_LARGE
+ }
+ }
+
+ private fun getReadableDuration(
+ duration: Duration,
+ @StringRes durationLessThanOneMinuteStringId: Int
+ ): String {
+ val hours = Math.toIntExact(duration.toHours())
+ val minutes = Math.toIntExact(duration.minusHours(hours.toLong()).toMinutes())
+ return when {
+ // Apply FormatWidth.WIDE if both the hour part and the minute part are non-zero.
+ hours > 0 && minutes > 0 ->
+ MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.NARROW)
+ .formatMeasures(
+ Measure(hours, MeasureUnit.HOUR),
+ Measure(minutes, MeasureUnit.MINUTE)
+ )
+ // Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
+ hours > 0 ->
+ MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
+ .formatMeasures(Measure(hours, MeasureUnit.HOUR))
+ // Apply FormatWidth.WIDE if only the minute part is non-zero (unless forced).
+ minutes > 0 ->
+ MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
+ .formatMeasures(Measure(minutes, MeasureUnit.MINUTE))
+ // Use a specific string for usage less than one minute but non-zero.
+ duration > Duration.ZERO -> context.getString(durationLessThanOneMinuteStringId)
+ // Otherwise, return 0-minute string.
+ else ->
+ MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
+ .formatMeasures(Measure(0, MeasureUnit.MINUTE))
+ }
+ }
+
+ /**
+ * Returns text to show for the banner depending on [.getSplitBannerConfig] If {@param
+ * forContentDesc} is `true`, this will always return the full string corresponding to
+ * [.SPLIT_BANNER_FULLSCREEN]
+ */
+ @JvmOverloads
+ @VisibleForTesting
+ fun getBannerText(
+ remainingTime: Long = appRemainingTimeMs,
+ forContentDesc: Boolean = false
+ ): String {
+ val duration =
+ Duration.ofMillis(
+ if (remainingTime > MINUTE_MS)
+ (remainingTime + MINUTE_MS - 1) / MINUTE_MS * MINUTE_MS
+ else remainingTime
+ )
+ val readableDuration =
+ getReadableDuration(
+ duration,
+ R.string.shorter_duration_less_than_one_minute /* forceFormatWidth */
+ )
+ val splitBannerConfig = getSplitBannerConfig()
+ return when {
+ forContentDesc || splitBannerConfig == SplitBannerConfig.SPLIT_BANNER_FULLSCREEN ->
+ context.getString(R.string.time_left_for_app, readableDuration)
+ // show no text
+ splitBannerConfig == SplitBannerConfig.SPLIT_GRID_BANNER_SMALL -> ""
+ // SPLIT_GRID_BANNER_LARGE only show time
+ else -> readableDuration
+ }
+ }
+
+ private fun openAppUsageSettings(view: View) {
+ val intent =
+ Intent(OPEN_APP_USAGE_SETTINGS_TEMPLATE)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, task.topComponent.packageName)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ try {
+ val options = ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.width, view.height)
+ context.startActivity(intent, options.toBundle())
+
+ // TODO: add WW logging on the app usage settings click.
+ } catch (e: ActivityNotFoundException) {
+ Log.e(
+ TAG,
+ "Failed to open app usage settings for task " + task.topComponent.packageName,
+ e
+ )
+ }
+ }
+
+ private fun getContentDescriptionForTask(
+ task: Task,
+ appUsageLimitTimeMs: Long,
+ appRemainingTimeMs: Long
+ ): String? =
+ if (appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0)
+ context.getString(
+ R.string.task_contents_description_with_remaining_time,
+ task.titleDescription,
+ getBannerText(appRemainingTimeMs, true /* forContentDesc */)
+ )
+ else task.titleDescription
+
+ fun setupLayout() {
+ val snapshotWidth: Int
+ val snapshotHeight: Int
+ val splitBounds = splitBounds
+ if (splitBounds == null) {
+ snapshotWidth = taskView.layoutParams.width
+ snapshotHeight =
+ taskView.layoutParams.height -
+ recentsViewContainer.deviceProfile.overviewTaskThumbnailTopMarginPx
+ } else {
+ val groupedTaskSize =
+ taskView.pagedOrientationHandler.getGroupedTaskViewSizes(
+ recentsViewContainer.deviceProfile,
+ splitBounds,
+ taskView.layoutParams.width,
+ taskView.layoutParams.height
+ )
+ if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+ snapshotWidth = groupedTaskSize.first.x
+ snapshotHeight = groupedTaskSize.first.y
+ } else {
+ snapshotWidth = groupedTaskSize.second.x
+ snapshotHeight = groupedTaskSize.second.y
+ }
+ }
+ taskView.pagedOrientationHandler.updateDwbBannerLayout(
+ taskView.layoutParams.width,
+ taskView.layoutParams.height,
+ taskView is GroupedTaskView,
+ recentsViewContainer.deviceProfile,
+ snapshotWidth,
+ snapshotHeight,
+ this
+ )
+ }
+
+ private fun setupTranslations() {
+ val (translationX, translationY) =
+ taskView.pagedOrientationHandler.getDwbBannerTranslations(
+ taskView.layoutParams.width,
+ taskView.layoutParams.height,
+ splitBounds,
+ recentsViewContainer.deviceProfile,
+ taskView.snapshotViews,
+ task.key.id,
+ this
+ )
+ this.translationX = translationX
+ this.splitOffsetTranslationY = translationY
+ }
+
+ private fun updateTranslationY() {
+ translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY
+ invalidateOutline()
+ }
+
+ fun setColorTint(color: Int, amount: Float) {
+ if (amount == 0f) {
+ setLayerType(View.LAYER_TYPE_NONE, null)
+ }
+ val layerPaint = Paint()
+ layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount))
+ setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint)
+ setLayerPaint(layerPaint)
+ }
+
+ private fun getAccessibilityActionId(): Int =
+ if (splitBounds?.rightBottomTaskId == task.key.id)
+ R.id.action_digital_wellbeing_bottom_right
+ else R.id.action_digital_wellbeing_top_left
+
+ fun getDWBAccessibilityAction(): AccessibilityNodeInfo.AccessibilityAction? {
+ if (!hasLimit) return null
+ val label =
+ if (taskView.containsMultipleTasks())
+ context.getString(
+ R.string.split_app_usage_settings,
+ TaskUtils.getTitle(context, task)
+ )
+ else context.getString(R.string.accessibility_app_usage_settings)
+ return AccessibilityNodeInfo.AccessibilityAction(getAccessibilityActionId(), label)
+ }
+
+ fun handleAccessibilityAction(action: Int): Boolean {
+ if (getAccessibilityActionId() != action) return false
+ openAppUsageSettings(taskView)
+ return true
+ }
+
+ companion object {
+ private const val THRESHOLD_LEFT_ICON_ONLY = 0.4f
+ private const val THRESHOLD_RIGHT_ICON_ONLY = 0.6f
+
+ enum class SplitBannerConfig {
+ /** Will span entire width of taskView with full text */
+ SPLIT_BANNER_FULLSCREEN,
+ /** Used for grid task view, only showing icon and time */
+ SPLIT_GRID_BANNER_LARGE,
+ /** Used for grid task view, only showing icon */
+ SPLIT_GRID_BANNER_SMALL
+ }
+
+ val OPEN_APP_USAGE_SETTINGS_TEMPLATE: Intent = Intent(Settings.ACTION_APP_USAGE_SETTINGS)
+ const val MINUTE_MS: Int = 60000
+
+ private const val TAG = "DigitalWellBeingToast"
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FixedSizeImageView.kt b/quickstep/src/com/android/quickstep/views/FixedSizeImageView.kt
new file mode 100644
index 0000000..c893016
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FixedSizeImageView.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.ViewGroup
+import android.widget.ImageView
+
+/**
+ * An [ImageView] that does not requestLayout() unless setLayoutParams is called.
+ *
+ * This is useful, particularly during animations, for [ImageView]s that are not supposed to be
+ * resized.
+ */
+@SuppressLint("AppCompatCustomView")
+class FixedSizeImageView : ImageView {
+ private var shouldRequestLayoutOnChanges = false
+
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ override fun setLayoutParams(params: ViewGroup.LayoutParams?) {
+ shouldRequestLayoutOnChanges = true
+ super.setLayoutParams(params)
+ shouldRequestLayoutOnChanges = false
+ }
+
+ override fun requestLayout() {
+ if (shouldRequestLayoutOnChanges) {
+ super.requestLayout()
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
index 4dde635..bdca596 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
@@ -123,8 +123,8 @@
@Override
public void onGlobalLayout() {
if (isUninitialized()) return;
- positionViews();
- if (mOnTargetChangeRunnable != null) {
+ boolean positionsChanged = positionViews();
+ if (mOnTargetChangeRunnable != null && positionsChanged) {
mOnTargetChangeRunnable.run();
}
}
@@ -212,21 +212,43 @@
onGlobalLayout();
}
- /** Sets the layout parameters of the floating view and its background view child. */
- private void positionViews() {
+ /**
+ * Sets the layout parameters of the floating view and its background view child.
+ * @return true if any of the views positions change due to this call.
+ */
+ private boolean positionViews() {
+ boolean positionsChanged = false;
+
LayoutParams layoutParams = (LayoutParams) getLayoutParams();
- layoutParams.setMargins(0, 0, 0, 0);
- setLayoutParams(layoutParams);
+
+ if (layoutParams.topMargin != 0 || layoutParams.bottomMargin != 0
+ || layoutParams.rightMargin != 0 || layoutParams.leftMargin != 0) {
+ positionsChanged = true;
+ layoutParams.setMargins(0, 0, 0, 0);
+ setLayoutParams(layoutParams);
+ }
// FloatingWidgetView layout is forced LTR
- mBackgroundView.setTranslationX(mBackgroundPosition.left);
- mBackgroundView.setTranslationY(mBackgroundPosition.top + mIconOffsetY);
+ float targetY = mBackgroundPosition.top + mIconOffsetY;
+ if (mBackgroundView.getTranslationX() != mBackgroundPosition.left
+ || mBackgroundView.getTranslationY() != targetY) {
+ positionsChanged = true;
+ mBackgroundView.setTranslationX(mBackgroundPosition.left);
+ mBackgroundView.setTranslationY(targetY);
+ }
+
LayoutParams backgroundParams = (LayoutParams) mBackgroundView.getLayoutParams();
- backgroundParams.leftMargin = 0;
- backgroundParams.topMargin = 0;
- backgroundParams.width = (int) mBackgroundPosition.width();
- backgroundParams.height = (int) mBackgroundPosition.height();
- mBackgroundView.setLayoutParams(backgroundParams);
+ if (backgroundParams.leftMargin != 0 || backgroundParams.topMargin != 0
+ || backgroundParams.width != Math.round(mBackgroundPosition.width())
+ || backgroundParams.height != Math.round(mBackgroundPosition.height())) {
+ positionsChanged = true;
+
+ backgroundParams.leftMargin = 0;
+ backgroundParams.topMargin = 0;
+ backgroundParams.width = Math.round(mBackgroundPosition.width());
+ backgroundParams.height = Math.round(mBackgroundPosition.height());
+ mBackgroundView.setLayoutParams(backgroundParams);
+ }
if (mForegroundOverlayView != null) {
sTmpMatrix.reset();
@@ -237,8 +259,15 @@
sTmpMatrix.postScale(foregroundScale, foregroundScale);
sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top
+ mIconOffsetY);
- mForegroundOverlayView.setMatrix(sTmpMatrix);
+
+ // We use the animation matrix here, because calling setMatrix on the GhostView
+ // actually sets the animation matrix, not the regular one.
+ if (!sTmpMatrix.equals(mForegroundOverlayView.getAnimationMatrix())) {
+ positionsChanged = true;
+ mForegroundOverlayView.setMatrix(sTmpMatrix);
+ }
}
+ return positionsChanged;
}
private void finish(DragLayer dragLayer) {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 6523ba7..3fd1a6b 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -36,7 +36,7 @@
import com.android.quickstep.util.SplitSelectStateController
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.system.InteractionJankMonitorWrapper
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition
+import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition
/**
* TaskView that contains and shows thumbnails for not one, BUT TWO(!!) tasks
@@ -115,6 +115,7 @@
R.id.snapshot,
R.id.icon,
R.id.show_windows,
+ R.id.digital_wellbeing_toast,
STAGE_POSITION_TOP_OR_LEFT,
taskOverlayFactory
),
@@ -123,6 +124,7 @@
R.id.bottomright_snapshot,
R.id.bottomRight_icon,
R.id.show_windows_right,
+ R.id.bottomRight_digital_wellbeing_toast,
STAGE_POSITION_BOTTOM_OR_RIGHT,
taskOverlayFactory
)
@@ -130,7 +132,7 @@
taskContainers.forEach { it.bind() }
this.splitBoundsConfig = splitBoundsConfig
- taskContainers.forEach { it.digitalWellBeingToast?.setSplitBounds(splitBoundsConfig) }
+ taskContainers.forEach { it.digitalWellBeingToast?.splitBounds = splitBoundsConfig }
setOrientationState(orientedState)
}
@@ -210,17 +212,13 @@
fun updateSplitBoundsConfig(splitBounds: SplitConfigurationOptions.SplitBounds?) {
splitBoundsConfig = splitBounds
taskContainers.forEach {
- it.digitalWellBeingToast?.setSplitBounds(splitBoundsConfig)
- it.digitalWellBeingToast?.initialize(it.task)
+ it.digitalWellBeingToast?.splitBounds = splitBoundsConfig
+ it.digitalWellBeingToast?.initialize()
}
invalidate()
}
- override fun launchTaskAnimated(): RunnableList? {
- if (taskContainers.isEmpty()) {
- Log.d(TAG, "launchTaskAnimated - task is not bound")
- return null
- }
+ override fun launchAsStaticTile(): RunnableList? {
val recentsView = recentsView ?: return null
val endCallback = RunnableList()
// Callbacks run from remote animation when recents animation not currently running
@@ -239,8 +237,11 @@
return endCallback
}
- override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
- launchTaskInternal(isQuickSwitch, false, callback /*launchingExistingTaskview*/)
+ override fun launchWithoutAnimation(
+ isQuickSwitch: Boolean,
+ callback: (launched: Boolean) -> Unit
+ ) {
+ launchTaskInternal(isQuickSwitch, launchingExistingTaskView = false, callback)
}
/**
@@ -264,7 +265,10 @@
isQuickSwitch,
snapPosition
)
- Log.d(TAG, "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}")
+ Log.d(
+ TAG,
+ "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}, launchingExistingTaskView: $launchingExistingTaskView"
+ )
}
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index d9468c7..4a2be2a 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -274,7 +274,9 @@
}
private void updateActionButtonsVisibility() {
- assert mDp != null;
+ if (mDp == null) {
+ return;
+ }
boolean showSingleTaskActions = !mIsGroupedTask;
boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair;
Log.d(TAG, "updateActionButtonsVisibility() called: showSingleTaskActions = ["
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5a6c278..e37e036 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -36,10 +36,13 @@
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
+import static com.android.launcher3.Flags.enableDesktopTaskAlphaAnimation;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile;
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 +60,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 +94,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;
@@ -208,6 +213,7 @@
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.util.RecentsViewUtils;
import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.SplitSelectStateController;
@@ -226,9 +232,9 @@
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.common.pip.IPipAnimationListener;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import kotlin.Unit;
@@ -251,8 +257,8 @@
* @param <CONTAINER_TYPE> : the container that should host recents view
* @param <STATE_TYPE> : the type of base state that will be used
*/
-
-public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewContainer,
+public abstract class RecentsView<
+ CONTAINER_TYPE extends Context & RecentsViewContainer,
STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
TaskVisualsChangeListener {
@@ -315,6 +321,27 @@
}
};
+ public static final FloatProperty<RecentsView> RUNNING_TASK_ATTACH_ALPHA =
+ new FloatProperty<RecentsView>("runningTaskAttachAlpha") {
+ @Override
+ public void setValue(RecentsView recentsView, float v) {
+ TaskView runningTask = recentsView.getRunningTaskView();
+ if (runningTask == null) {
+ return;
+ }
+ runningTask.setAttachAlpha(v);
+ }
+
+ @Override
+ public Float get(RecentsView recentsView) {
+ TaskView runningTask = recentsView.getRunningTaskView();
+ if (runningTask == null) {
+ return null;
+ }
+ return runningTask.getAttachAlpha();
+ }
+ };
+
public static final int SCROLL_VIBRATION_PRIMITIVE =
Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
@@ -608,13 +635,16 @@
@Override
public void onTaskRemoved(int taskId) {
if (!mHandleTaskStackChanges) {
+ Log.d(TAG, "onTaskRemoved: " + taskId + ", not handling task stack changes");
return;
}
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView == null) {
+ Log.d(TAG, "onTaskRemoved: " + taskId + ", no associated TaskView");
return;
}
+ Log.d(TAG, "onTaskRemoved: " + taskId);
Task.TaskKey taskKey = taskView.getFirstTask().key;
UI_HELPER_EXECUTOR.execute(new CancellableTask<>(
() -> PackageManagerWrapper.getInstance()
@@ -653,7 +683,7 @@
protected boolean mRunningTaskTileHidden;
@Nullable
private Task[] mTmpRunningTasks;
- protected int mFocusedTaskViewId = -1;
+ protected int mFocusedTaskViewId = INVALID_TASK_ID;
private boolean mTaskIconScaledDown = false;
private boolean mRunningTaskShowScreenshot = false;
@@ -810,7 +840,8 @@
private boolean mAnyTaskHasBeenDismissed;
private final RecentsViewModel mRecentsViewModel;
- private final RecentsViewHelper mHelper;
+ private final RecentsViewModelHelper mHelper;
+ private final RecentsViewUtils mUtils = new RecentsViewUtils();
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
BaseContainerInterface sizeStrategy) {
@@ -832,7 +863,7 @@
recentsDependencies.inject(RecentTasksRepository.class),
recentsDependencies.inject(RecentsViewData.class)
);
- mHelper = new RecentsViewHelper(mRecentsViewModel);
+ mHelper = new RecentsViewModelHelper(mRecentsViewModel);
recentsDependencies.provide(RecentsRotationStateRepository.class,
() -> new RecentsRotationStateRepositoryImpl(mOrientationState));
@@ -1050,7 +1081,6 @@
@Nullable
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
if (enableRefactorTaskThumbnail()) {
- mHelper.onTaskThumbnailChanged(taskId, thumbnailData);
return null;
}
if (mHandleTaskStackChanges) {
@@ -1071,16 +1101,14 @@
}
@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();
+ public void onTaskIconChanged(@NonNull String pkg, @NonNull UserHandle user) {
+ for (TaskView taskView : getTaskViews()) {
+ Task task = taskView.getFirstTask();
if (pkg.equals(task.key.getPackageName()) && task.key.userId == user.getIdentifier()) {
task.icon = null;
- if (tv.getTaskContainers().stream().anyMatch(
+ if (taskView.getTaskContainers().stream().anyMatch(
container -> container.getIconView().getDrawable() != null)) {
- tv.onTaskListVisibilityChanged(true /* visible */);
+ taskView.onTaskListVisibilityChanged(true /* visible */);
}
}
}
@@ -1469,8 +1497,7 @@
return null;
}
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
if (taskView.containsTaskId(taskId)) {
return taskView;
}
@@ -1491,8 +1518,7 @@
int[] taskIdsCopy = Arrays.copyOf(taskIds, taskIds.length);
Arrays.sort(taskIdsCopy);
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
int[] taskViewIdsCopy = taskView.getTaskIds();
Arrays.sort(taskViewIdsCopy);
if (Arrays.equals(taskIdsCopy, taskViewIdsCopy)) {
@@ -1528,9 +1554,7 @@
*/
public void setTaskBorderEnabled(boolean enabled) {
mBorderEnabled = enabled;
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
taskView.setBorderEnabled(enabled);
}
mClearAllButton.setBorderEnabled(enabled);
@@ -1597,9 +1621,7 @@
super.onTouchEvent(ev);
if (showAsGrid()) {
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
if (isTaskViewVisible(taskView) && taskView.offerTouchToChildren(ev)) {
// Keep consuming events to pass to delegate
return true;
@@ -1682,10 +1704,10 @@
}
TaskView taskView = getTaskViewAt(mNextPage);
// Snap to fully visible focused task and clear all button.
- boolean shouldSnapToFocusedTask = taskView != null && taskView.isFocusedTask()
+ boolean shouldSnapToLargeTask = taskView != null && taskView.isLargeTile()
&& isTaskViewFullyVisible(taskView);
boolean shouldSnapToClearAll = mNextPage == indexOfChild(mClearAllButton);
- if (!shouldSnapToFocusedTask && !shouldSnapToClearAll) {
+ if (!shouldSnapToLargeTask && !shouldSnapToClearAll) {
return;
}
}
@@ -1745,7 +1767,9 @@
return;
}
- if (mCurrentPage == 0) {
+ int frontIndex = enableLargeDesktopWindowingTile() ? getDesktopTaskViewCount() : 0;
+
+ if (mCurrentPage <= frontIndex) {
return;
}
@@ -1757,8 +1781,9 @@
removeView(runningTaskView);
mMovingTaskView = null;
runningTaskView.resetPersistentViewTransforms();
- addView(runningTaskView, 0);
- setCurrentPage(0);
+
+ addView(runningTaskView, frontIndex);
+ setCurrentPage(frontIndex);
updateTaskSize();
}
@@ -1776,7 +1801,8 @@
protected void applyLoadPlan(List<GroupTask> taskGroups) {
if (mPendingAnimation != null) {
- mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
+ final List<GroupTask> finalTaskGroups = taskGroups;
+ mPendingAnimation.addEndListener(success -> applyLoadPlan(finalTaskGroups));
return;
}
@@ -1821,12 +1847,15 @@
// Reset the focused task to avoiding initializing TaskViews layout as focused task during
// binding. The focused task view will be updated after all the TaskViews are bound.
- mFocusedTaskViewId = INVALID_TASK_ID;
+ setFocusedTaskViewId(INVALID_TASK_ID);
// Removing views sets the currentPage to 0, so we save this and restore it after
// the new set of views are added
int previousCurrentPage = mCurrentPage;
int previousFocusedPage = indexOfChild(getFocusedChild());
+ // TaskIds will no longer be valid after remove and re-add, clearing mTopRowIdSet.
+ mAnyTaskHasBeenDismissed = false;
+ mTopRowIdSet.clear();
removeAllViews();
// If we are entering Overview as a result of initiating a split from somewhere else
@@ -1844,6 +1873,11 @@
// Clear out desktop view if it is set
mDesktopTaskView = null;
+ // Move Desktop Tasks to the end of the list
+ if (enableLargeDesktopWindowingTile()) {
+ taskGroups = mUtils.sortDesktopTasksToFront(taskGroups);
+ }
+
// Add views as children based on whether it's grouped or single task. Looping through
// taskGroups backwards populates the thumbnail grid from least recent to most recent.
for (int i = taskGroups.size() - 1; i >= 0; i--) {
@@ -1897,11 +1931,14 @@
// Keep same previous focused task
TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskIds);
// If the list changed, maybe the focused task doesn't exist anymore
- if (newFocusedTaskView == null && getTaskViewCount() > 0) {
- newFocusedTaskView = getTaskViewAt(0);
+ int newFocusedTaskViewIndex = mUtils.getFocusedTaskIndex(taskGroups);
+ if (newFocusedTaskView == null && getTaskViewCount() > newFocusedTaskViewIndex) {
+ newFocusedTaskView = getTaskViewAt(newFocusedTaskViewIndex);
}
- mFocusedTaskViewId = newFocusedTaskView != null && !enableGridOnlyOverview()
- ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID;
+
+ setFocusedTaskViewId(newFocusedTaskView != null && !enableGridOnlyOverview()
+ ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID);
+
updateTaskSize();
updateChildTaskOrientations();
@@ -1941,8 +1978,8 @@
// Set the current page to the running task, but not if settling on new task.
if (hasAllValidTaskIds(runningTaskIds)) {
targetPage = indexOfChild(newRunningTaskView);
- } else if (getTaskViewCount() > 0) {
- targetPage = indexOfChild(requireTaskViewAt(0));
+ } else if (getTaskViewCount() > newFocusedTaskViewIndex) {
+ targetPage = indexOfChild(requireTaskViewAt(newFocusedTaskViewIndex));
}
}
if (targetPage != -1 && mCurrentPage != targetPage) {
@@ -1967,6 +2004,7 @@
// generally map to the same task.
mIgnoreResetTaskId = INVALID_TASK_ID;
}
+
resetTaskVisuals();
onTaskStackUpdated();
updateEnabledOverlays();
@@ -1984,15 +2022,13 @@
}
private void removeTasksViewsAndClearAllButton() {
- // This handles an edge case where applyLoadPlan happens during a gesture when the
- // only Task is one with excludeFromRecents, in which case we should not remove it.
- final int stubRunningTaskIndex = isGestureActive() ? getRunningTaskIndex() : -1;
-
- for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- if (i == stubRunningTaskIndex) {
+ for (TaskView taskView : getTaskViews()) {
+ if (isGestureActive() && taskView.isRunningTask()) {
+ // This handles an edge case where applyLoadPlan happens during a gesture when the
+ // only Task is one with excludeFromRecents, in which case we should not remove it.
continue;
}
- removeView(requireTaskViewAt(i));
+ removeView(taskView);
}
if (getTaskViewCount() == 0 && indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
@@ -2007,14 +2043,13 @@
return taskViewCount;
}
- public int getGroupedTaskViewCount() {
- int groupViewCount = 0;
- for (int i = 0; i < getChildCount(); i++) {
- if (getChildAt(i) instanceof GroupedTaskView) {
- groupViewCount++;
- }
- }
- return groupViewCount;
+ /**
+ * Transverse RecentsView children to calculate the amount of DesktopTaskViews.
+ *
+ * @return Number of children that are instances of DesktopTaskView
+ */
+ private int getDesktopTaskViewCount() {
+ return mUtils.getDesktopTaskViewCount(getTaskViews());
}
/**
@@ -2037,8 +2072,7 @@
}
public void resetTaskVisuals() {
- for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
if (Arrays.stream(taskView.getTaskIds()).noneMatch(
taskId -> taskId == mIgnoreResetTaskId)) {
taskView.resetViewTransforms();
@@ -2081,9 +2115,8 @@
if (enableRefactorTaskThumbnail()) {
mRecentsViewModel.updateFullscreenProgress(mFullscreenProgress);
}
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.setFullscreenProgress(mFullscreenProgress);
}
mClearAllButton.setFullscreenProgress(fullscreenProgress);
@@ -2096,6 +2129,7 @@
boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow()
&& getWindowVisibility() == VISIBLE;
if (handleTaskStackChanges != mHandleTaskStackChanges) {
+ Log.d(TAG, "updateTaskStackListenerState: " + handleTaskStackChanges);
mHandleTaskStackChanges = handleTaskStackChanges;
if (handleTaskStackChanges) {
reloadIfNeeded();
@@ -2228,8 +2262,7 @@
? mLastComputedCarouselTaskSize.right - mLastComputedTaskSize.right
: mLastComputedCarouselTaskSize.left - mLastComputedTaskSize.left;
}
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
taskView.updateTaskSize(mLastComputedTaskSize, mLastComputedGridTaskSize,
mLastComputedCarouselTaskSize);
taskView.setNonGridTranslationX(accumulatedTranslationX);
@@ -2505,7 +2538,6 @@
}
if (enableRefactorTaskThumbnail()) {
- // TODO(b/342560598): Listen in TaskRepository and reload.
return;
}
@@ -2546,7 +2578,7 @@
mCurrentPageScrollDiff = 0;
mIgnoreResetTaskId = -1;
mTaskListChangeId = -1;
- mFocusedTaskViewId = -1;
+ setFocusedTaskViewId(INVALID_TASK_ID);
mAnyTaskHasBeenDismissed = false;
@@ -2618,14 +2650,17 @@
return getTaskViewFromTaskViewId(mFocusedTaskViewId);
}
+ private @Nullable TaskView getFirstLargeTaskView() {
+ return mUtils.getFirstLargeTaskView(getTaskViews());
+ }
+
@Nullable
private TaskView getTaskViewFromTaskViewId(int taskViewId) {
if (taskViewId == -1) {
return null;
}
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
if (taskView.getTaskViewId() == taskViewId) {
return taskView;
}
@@ -2686,9 +2721,12 @@
if (!mModel.isTaskListValid(mTaskListChangeId)) {
mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState
.getFilter(mFilterState.getPackageNameToFilter()));
+ Log.d(TAG, "reloadIfNeeded - getTasks: " + mTaskListChangeId);
if (enableRefactorTaskThumbnail()) {
mRecentsViewModel.refreshAllTaskData();
}
+ } else {
+ Log.d(TAG, "reloadIfNeeded - task list still valid: " + mTaskListChangeId);
}
}
@@ -2711,10 +2749,17 @@
showCurrentTask(mActiveGestureRunningTasks);
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
- setRunningTaskHidden(true);
+ setRunningTaskHidden(!shouldUpdateRunningTaskAlpha());
setTaskIconScaledDown(true);
}
+ /**
+ * Returns whether the running task's attach alpha should be updated during the attach animation
+ */
+ public boolean shouldUpdateRunningTaskAlpha() {
+ return enableDesktopTaskAlphaAnimation() && getRunningTaskView() instanceof DesktopTaskView;
+ }
+
private boolean isGestureActive() {
return mActiveGestureRunningTasks != null;
}
@@ -2764,8 +2809,8 @@
}
private void updateChildTaskOrientations() {
- for (int i = 0; i < getTaskViewCount(); i++) {
- requireTaskViewAt(i).setOrientationState(mOrientationState);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.setOrientationState(mOrientationState);
}
boolean shouldRotateMenuForFakeRotation =
!mOrientationState.isRecentsActivityRotationAllowed();
@@ -2879,6 +2924,7 @@
if (runningTasks.length == 0) {
return;
}
+
int runningTaskViewId = -1;
boolean needGroupTaskView = runningTasks.length > 1;
boolean needDesktopTask = hasDesktopTask(runningTasks);
@@ -2923,7 +2969,11 @@
boolean runningTaskTileHidden = mRunningTaskTileHidden;
setCurrentTask(runningTaskViewId);
- mFocusedTaskViewId = enableGridOnlyOverview() ? INVALID_TASK_ID : runningTaskViewId;
+
+ boolean shouldFocusRunningTask = !(enableGridOnlyOverview()
+ || (enableLargeDesktopWindowingTile()
+ && getRunningTaskView() instanceof DesktopTaskView));
+ setFocusedTaskViewId(shouldFocusRunningTask ? runningTaskViewId : INVALID_TASK_ID);
runOnPageScrollsInitialized(() -> setCurrentPage(getRunningTaskIndex()));
setRunningTaskViewShowScreenshot(false);
setRunningTaskHidden(runningTaskTileHidden);
@@ -2975,6 +3025,10 @@
}
}
+ private void setFocusedTaskViewId(int viewId) {
+ mFocusedTaskViewId = viewId;
+ }
+
private int getTaskViewIdFromTaskId(int taskId) {
TaskView taskView = getTaskViewByTaskId(taskId);
return taskView != null ? taskView.getTaskViewId() : -1;
@@ -2986,20 +3040,26 @@
public void setRunningTaskHidden(boolean isHidden) {
mRunningTaskTileHidden = isHidden;
TaskView runningTask = getRunningTaskView();
- if (runningTask != null) {
- runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha);
- if (!isHidden) {
- AccessibilityManagerCompat.sendCustomAccessibilityEvent(runningTask,
- AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
- }
+ if (runningTask == null) {
+ return;
+ }
+ runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha);
+ if (!isHidden) {
+ AccessibilityManagerCompat.sendCustomAccessibilityEvent(
+ runningTask, AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
}
}
private void setRunningTaskViewShowScreenshot(boolean showScreenshot) {
+ setRunningTaskViewShowScreenshot(showScreenshot, /*updatedThumbnails=*/null);
+ }
+
+ private void setRunningTaskViewShowScreenshot(boolean showScreenshot,
+ @Nullable Map<Integer, ThumbnailData> updatedThumbnails) {
mRunningTaskShowScreenshot = showScreenshot;
TaskView runningTaskView = getRunningTaskView();
if (runningTaskView != null) {
- runningTaskView.setShouldShowScreenshot(mRunningTaskShowScreenshot);
+ runningTaskView.setShouldShowScreenshot(mRunningTaskShowScreenshot, updatedThumbnails);
}
if (enableRefactorTaskThumbnail()) {
mRecentsViewModel.setRunningTaskShowScreenshot(showScreenshot);
@@ -3009,9 +3069,8 @@
public void setTaskIconScaledDown(boolean isScaledDown) {
if (mTaskIconScaledDown != isScaledDown) {
mTaskIconScaledDown = isScaledDown;
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- requireTaskViewAt(i).setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
}
}
}
@@ -3024,9 +3083,7 @@
public void animateUpTaskIconScale() {
mTaskIconScaledDown = false;
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
taskView.animateIconScaleAndDimIntoView();
}
}
@@ -3074,8 +3131,9 @@
float[] gridTranslations = new float[taskCount];
int focusedTaskIndex = Integer.MAX_VALUE;
+ Set<Integer> largeTasksIndices = new HashSet<>();
int focusedTaskShift = 0;
- int focusedTaskWidthAndSpacing = 0;
+ int largeTaskWidthAndSpacing = 0;
int snappedTaskRowWidth = 0;
int snappedPage = isKeyboardTaskFocusPending() ? mKeyboardTaskFocusIndex : getNextPage();
TaskView snappedTaskView = getTaskViewAt(snappedPage);
@@ -3092,12 +3150,11 @@
// Evenly distribute tasks between rows unless rearranging due to task dismissal, in
// which case keep tasks in their respective rows. For the running task, don't join
// the grid.
- if (taskView.isFocusedTask()) {
+ boolean isLargeTile = taskView.isLargeTile();
+
+ if (isLargeTile) {
topRowWidth += taskWidthAndSpacing;
bottomRowWidth += taskWidthAndSpacing;
-
- focusedTaskIndex = i;
- focusedTaskWidthAndSpacing = taskWidthAndSpacing;
gridTranslations[i] += focusedTaskShift;
gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
@@ -3105,6 +3162,12 @@
taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
- taskView.getLayoutParams().height) / 2f);
+ if (taskView.getTaskViewId() == mFocusedTaskViewId) {
+ focusedTaskIndex = i;
+ }
+ largeTasksIndices.add(i);
+ largeTaskWidthAndSpacing = taskWidthAndSpacing;
+
if (taskView == snappedTaskView) {
// If focused task is snapped, the row width is just task width and spacing.
snappedTaskRowWidth = taskWidthAndSpacing;
@@ -3113,7 +3176,7 @@
if (i > focusedTaskIndex) {
// For tasks after the focused task, shift by focused task's width and spacing.
gridTranslations[i] +=
- mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
+ mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing;
} else {
// For task before the focused task, accumulate the width and spacing to
// calculate the distance focused task need to shift.
@@ -3149,7 +3212,7 @@
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
- if (j == focusedTaskIndex) {
+ if (largeTasksIndices.contains(j)) {
continue;
}
widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -3168,7 +3231,7 @@
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
- if (j == focusedTaskIndex) {
+ if (largeTasksIndices.contains(j)) {
continue;
}
widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -3218,12 +3281,22 @@
// accordingly. Update longRowWidth if ClearAllButton has been moved.
float clearAllShortTotalWidthTranslation = 0;
int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
- if (longRowWidth < mLastComputedGridSize.width()) {
- mClearAllShortTotalWidthTranslation =
- (mIsRtl
- ? mLastComputedTaskSize.right
- : deviceProfile.widthPx - mLastComputedTaskSize.left)
- - longRowWidth - deviceProfile.overviewGridSideMargin;
+
+ // If Recents contains only large task sizes, it should only consider 1 large size
+ // for ClearAllButton translation. The space at the left side of the large task will be
+ // empty and it should be move ClearAllButton further away as well.
+ // TODO(b/359573248): Validate the translation for ClearAllButton for grid only.
+ boolean hasOnlyLargeTasks = taskCount == largeTasksIndices.size();
+ if (enableLargeDesktopWindowingTile() && hasOnlyLargeTasks) {
+ longRowWidth = largeTaskWidthAndSpacing;
+ }
+
+ // If first task is not in the expected position (mLastComputedTaskSize) and being too close
+ // to ClearAllButton, then apply extra translation to ClearAllButton.
+ int firstTaskStart = mLastComputedGridSize.left + longRowWidth;
+ int expectedFirstTaskStart = mLastComputedTaskSize.right;
+ if (firstTaskStart < expectedFirstTaskStart) {
+ mClearAllShortTotalWidthTranslation = expectedFirstTaskStart - firstTaskStart;
clearAllShortTotalWidthTranslation = mIsRtl
? -mClearAllShortTotalWidthTranslation : mClearAllShortTotalWidthTranslation;
if (snappedTaskRowWidth == longRowWidth) {
@@ -3238,10 +3311,10 @@
float clearAllTotalTranslationX =
clearAllAccumulatedTranslation + clearAllShorterRowCompensation
+ clearAllShortTotalWidthTranslation + snappedTaskNonGridScrollAdjustment;
- if (focusedTaskIndex < taskCount) {
+ if (!largeTasksIndices.isEmpty()) {
// Shift by focused task's width and spacing if a task is focused.
clearAllTotalTranslationX +=
- mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
+ mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing;
}
// Make sure there are enough space between snapped page and ClearAllButton, for the case
@@ -3281,7 +3354,6 @@
mClearAllButton.setGridScrollOffset(
mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
: mLastComputedTaskSize.right - mLastComputedGridSize.right);
-
setGridProgress(mGridProgress);
}
@@ -3289,11 +3361,11 @@
if (taskView1 == null || taskView2 == null) {
return false;
}
- int taskViewId1 = taskView1.getTaskViewId();
- int taskViewId2 = taskView2.getTaskViewId();
- if (taskViewId1 == mFocusedTaskViewId || taskViewId2 == mFocusedTaskViewId) {
+ if (taskView1.isLargeTile() || taskView2.isLargeTile()) {
return false;
}
+ int taskViewId1 = taskView1.getTaskViewId();
+ int taskViewId2 = taskView2.getTaskViewId();
return (mTopRowIdSet.contains(taskViewId1) && mTopRowIdSet.contains(taskViewId2)) || (
!mTopRowIdSet.contains(taskViewId1) && !mTopRowIdSet.contains(taskViewId2));
}
@@ -3306,9 +3378,8 @@
private void setGridProgress(float gridProgress) {
mGridProgress = gridProgress;
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- requireTaskViewAt(i).setGridProgress(gridProgress);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.setGridProgress(gridProgress);
}
mClearAllButton.setGridProgress(gridProgress);
}
@@ -3318,14 +3389,10 @@
mRecentsViewModel.updateThumbnailSplashProgress(taskThumbnailSplashAlpha);
return;
}
- int taskCount = getTaskViewCount();
- if (taskCount == 0) {
- return;
- }
mTaskThumbnailSplashAlpha = taskThumbnailSplashAlpha;
- for (int i = 0; i < taskCount; i++) {
- requireTaskViewAt(i).setTaskThumbnailSplashAlpha(taskThumbnailSplashAlpha);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.setTaskThumbnailSplashAlpha(taskThumbnailSplashAlpha);
}
}
@@ -3447,6 +3514,7 @@
mSplitSelectStateController.getSplitAnimationController().
playAnimPlaceholderToFullscreen(mContainer, view,
Optional.of(() -> resetFromSplitSelectionState())));
+ firstFloatingTaskView.setContentDescription(splitAnimInitProps.getContentDescription());
// SplitInstructionsView: animate in
safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
@@ -3545,11 +3613,10 @@
isStagingFocusedTask = true;
} else {
nextFocusedTaskFromTop =
- mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
+ !mTopRowIdSet.isEmpty() && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
// Pick the next focused task from the preferred row.
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
- if (taskView == dismissedTaskView) {
+ for (TaskView taskView : getTaskViews()) {
+ if (taskView == dismissedTaskView || taskView.isLargeTile()) {
continue;
}
boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
@@ -3676,8 +3743,7 @@
END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+ (taskCount - 1) * halfAdditionalDismissTranslationOffset,
END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
anim.setFloat(taskView, TaskView.GRID_END_TRANSLATION_X, longGridRowWidthDiff,
clampToProgress(LINEAR, dismissTranslationInterpolationEnd, 1));
dismissTranslationInterpolationEnd = Utilities.boundToRange(
@@ -4013,9 +4079,9 @@
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
- mFocusedTaskViewId = enableGridOnlyOverview()
+ setFocusedTaskViewId(enableGridOnlyOverview()
? INVALID_TASK_ID
- : finalNextFocusedTaskView.getTaskViewId();
+ : finalNextFocusedTaskView.getTaskViewId());
mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
@@ -4137,9 +4203,8 @@
return new IntArray(0);
}
IntArray topArray = new IntArray(mTopRowIdSet.size());
- int taskViewCount = getTaskViewCount();
- for (int i = 0; i < taskViewCount; i++) {
- int taskViewId = requireTaskViewAt(i).getTaskViewId();
+ for (TaskView taskView : getTaskViews()) {
+ int taskViewId = taskView.getTaskViewId();
if (mTopRowIdSet.contains(taskViewId)) {
topArray.add(taskViewId);
}
@@ -4156,10 +4221,9 @@
return new IntArray(0);
}
IntArray bottomArray = new IntArray(bottomRowIdArraySize);
- int taskViewCount = getTaskViewCount();
- for (int i = 0; i < taskViewCount; i++) {
- int taskViewId = requireTaskViewAt(i).getTaskViewId();
- if (!mTopRowIdSet.contains(taskViewId) && taskViewId != mFocusedTaskViewId) {
+ for (TaskView taskView : getTaskViews()) {
+ int taskViewId = taskView.getTaskViewId();
+ if (!mTopRowIdSet.contains(taskViewId) && !taskView.isLargeTile()) {
bottomArray.add(taskViewId);
}
}
@@ -4217,9 +4281,8 @@
}
PendingAnimation anim = new PendingAnimation(duration);
- int count = getTaskViewCount();
- for (int i = 0; i < count; i++) {
- addDismissedTaskAnimations(requireTaskViewAt(i), duration, anim);
+ for (TaskView taskView : getTaskViews()) {
+ addDismissedTaskAnimations(taskView, duration, anim);
}
mPendingAnimation = anim;
@@ -4266,7 +4329,7 @@
// Init task grid nav helper with top/bottom id arrays.
TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(),
- getBottomRowIdArray(), mFocusedTaskViewId);
+ getBottomRowIdArray(), mUtils.getLargeTaskViewIds(getTaskViews()));
// Get current page's task view ID.
TaskView currentPageTaskView = getCurrentPageTaskView();
@@ -4297,8 +4360,10 @@
private void dismissTask(int taskId) {
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView == null) {
+ Log.d(TAG, "dismissTask: " + taskId + ", no associated TaskView");
return;
}
+ Log.d(TAG, "dismissTask: " + taskId);
dismissTask(taskView, true /* animate */, false /* removeTask */);
}
@@ -4383,12 +4448,11 @@
mContentAlpha = alpha;
TaskView runningTaskView = getRunningTaskView();
- for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- TaskView child = requireTaskViewAt(i);
- if (runningTaskView != null && mRunningTaskTileHidden && child == runningTaskView) {
+ for (TaskView taskView : getTaskViews()) {
+ if (runningTaskView != null && mRunningTaskTileHidden && taskView == runningTaskView) {
continue;
}
- child.setStableAlpha(alpha);
+ taskView.setStableAlpha(alpha);
}
mClearAllButton.setContentAlpha(mContentAlpha);
int alphaInt = Math.round(alpha * 255);
@@ -4497,6 +4561,13 @@
return Objects.requireNonNull(getTaskViewAt(index));
}
+ /**
+ * Returns the current list of [TaskView] children.
+ */
+ private List<TaskView> getTaskViews() {
+ return mUtils.getTaskViews(getTaskViewCount(), this::requireTaskViewAt);
+ }
+
public void setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener listener) {
mOnEmptyMessageUpdatedListener = listener;
}
@@ -4593,9 +4664,10 @@
? (runningTask == null ? INVALID_PAGE : indexOfChild(runningTask))
: mOffsetMidpointIndexOverride;
int modalMidpoint = getCurrentPage();
- boolean isModalGridWithoutFocusedTask =
- showAsGrid && enableGridOnlyOverview() && mTaskModalness > 0;
- if (isModalGridWithoutFocusedTask) {
+ boolean shouldCalculateOffsetForAllTasks = showAsGrid
+ && (enableGridOnlyOverview() || enableLargeDesktopWindowingTile())
+ && mTaskModalness > 0;
+ if (shouldCalculateOffsetForAllTasks) {
modalMidpoint = indexOfChild(mSelectedTask);
}
@@ -4634,7 +4706,7 @@
: i < midpoint
? leftOffsetSize
: rightOffsetSize;
- if (isModalGridWithoutFocusedTask) {
+ if (shouldCalculateOffsetForAllTasks) {
gridOffsetSize = getHorizontalOffsetSize(i, modalMidpoint, modalOffset);
gridOffsetSize = Math.abs(gridOffsetSize) * (i <= modalMidpoint ? 1 : -1);
}
@@ -4643,8 +4715,11 @@
: showAsGrid
? gridOffsetSize
: i < modalMidpoint ? modalLeftOffsetSize : modalRightOffsetSize;
- float totalTranslationX = translation + modalTranslation;
View child = getChildAt(i);
+ boolean skipTranslationOffset = enableDesktopTaskAlphaAnimation()
+ && i == getRunningTaskIndex()
+ && child instanceof DesktopTaskView;
+ float totalTranslationX = (skipTranslationOffset ? 0f : translation) + modalTranslation;
FloatProperty translationPropertyX = child instanceof TaskView
? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
: getPagedOrientationHandler().getPrimaryViewTranslate();
@@ -4797,9 +4872,9 @@
protected void setTaskViewsResistanceTranslation(float translation) {
mTaskViewsSecondaryTranslation = translation;
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView task = requireTaskViewAt(i);
- task.getTaskResistanceTranslationProperty().set(task, translation / getScaleY());
+ for (TaskView taskView : getTaskViews()) {
+ taskView.getTaskResistanceTranslationProperty().set(taskView,
+ translation / getScaleY());
}
runActionOnRemoteHandles(
remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
@@ -4807,23 +4882,21 @@
}
private void updateTaskViewsSnapshotRadius() {
- for (int i = 0; i < getTaskViewCount(); i++) {
- requireTaskViewAt(i).updateSnapshotRadius();
+ for (TaskView taskView : getTaskViews()) {
+ taskView.updateSnapshotRadius();
}
}
protected void setTaskViewsPrimarySplitTranslation(float translation) {
mTaskViewsPrimarySplitTranslation = translation;
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView task = requireTaskViewAt(i);
- task.getPrimarySplitTranslationProperty().set(task, translation);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.getPrimarySplitTranslationProperty().set(taskView, translation);
}
}
protected void setTaskViewsSecondarySplitTranslation(float translation) {
mTaskViewsSecondarySplitTranslation = translation;
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
if (taskView == mSplitHiddenTaskView && !taskView.containsMultipleTasks()) {
continue;
}
@@ -4880,7 +4953,7 @@
mSplitSelectStateController.setDismissingFromSplitPair(mSplitHiddenTaskView != null
&& mSplitHiddenTaskView instanceof GroupedTaskView);
mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
- splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
+ splitSelectSource.position.stagePosition, splitSelectSource.getItemInfo(),
splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
updateDesktopTaskVisibility(false /* visible */);
}
@@ -5232,23 +5305,34 @@
* 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)
- : taskIndex == centerTaskIndex;
- if (launchingCenterTask) {
+ boolean zoomInTaskView = showAsGrid ? taskView.isLargeTile() : taskIndex == centerTaskIndex;
+ 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));
@@ -5276,6 +5360,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;
}
@@ -5301,7 +5396,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");
}
@@ -5316,13 +5411,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 {
@@ -5330,8 +5425,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,
@@ -5341,19 +5435,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);
@@ -5362,9 +5444,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(
@@ -5374,13 +5465,13 @@
dividerAnimator.end();
});
}
- if (tv.isRunningTask()) {
+ if (taskView.isRunningTask()) {
finishRecentsAnimation(false /* toRecents */, null);
onTaskLaunchAnimationEnd(true /* success */);
} else {
- tv.launchTask(this::onTaskLaunchAnimationEnd);
+ taskView.launchWithoutAnimation(this::onTaskLaunchAnimationEnd);
}
- mContainer.getStatsLogManager().logger().withItemInfo(tv.getFirstItemInfo())
+ mContainer.getStatsLogManager().logger().withItemInfo(taskView.getFirstItemInfo())
.log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
} else {
onTaskLaunchAnimationEnd(false);
@@ -5703,8 +5794,8 @@
}
private int getFirstViewIndex() {
- TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
- return focusedTaskView != null ? indexOfChild(focusedTaskView) : 0;
+ TaskView firstTaskView = mShowAsGridLastOnLayout ? getFirstLargeTaskView() : null;
+ return firstTaskView != null ? indexOfChild(firstTaskView) : 0;
}
private int getLastViewIndex() {
@@ -5722,7 +5813,7 @@
}
// Returns focus task if there are no grid tasks.
- return indexOfChild(getFocusedTaskView());
+ return indexOfChild(getFirstLargeTaskView());
}
/**
@@ -5938,7 +6029,7 @@
public boolean isOnGridBottomRow(TaskView taskView) {
return showAsGrid()
&& !mTopRowIdSet.contains(taskView.getTaskViewId())
- && taskView.getTaskViewId() != mFocusedTaskViewId;
+ && !taskView.isLargeTile();
}
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
@@ -5972,9 +6063,7 @@
private void updateEnabledOverlays() {
TaskView focusedTaskView = getFocusedTaskView();
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (TaskView taskView : getTaskViews()) {
if (taskView == focusedTaskView) {
continue;
}
@@ -6048,20 +6137,12 @@
return;
}
+ Map<Integer, ThumbnailData> updatedThumbnails = mUtils.screenshotTasks(taskView,
+ mRecentsAnimationController);
if (enableRefactorTaskThumbnail()) {
- mHelper.switchToScreenshot(taskView, mRecentsAnimationController, onFinishRunnable);
+ mHelper.switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable);
} else {
- setRunningTaskViewShowScreenshot(true);
- for (TaskContainer container : taskView.getTaskContainers()) {
- ThumbnailData thumbnailData =
- mRecentsAnimationController.screenshotTask(container.getTask().key.id);
- TaskThumbnailViewDeprecated thumbnailView = container.getThumbnailViewDeprecated();
- if (thumbnailData != null) {
- thumbnailView.setThumbnail(container.getTask(), thumbnailData);
- } else {
- thumbnailView.refresh();
- }
- }
+ setRunningTaskViewShowScreenshot(true, updatedThumbnails);
ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
}
}
@@ -6080,8 +6161,7 @@
if (enableRefactorTaskThumbnail()) {
mHelper.switchToScreenshot(taskView, thumbnailDatas, onFinishRunnable);
} else {
- taskView.setShouldShowScreenshot(true);
- taskView.refreshThumbnails(thumbnailDatas);
+ taskView.setShouldShowScreenshot(true, thumbnailDatas);
ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
}
} else {
@@ -6155,8 +6235,8 @@
mRecentsViewModel.setTintAmount(tintAmount);
}
- for (int i = 0; i < getTaskViewCount(); i++) {
- requireTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
+ for (TaskView taskView : getTaskViews()) {
+ taskView.setColorTint(mColorTint, mTintingColor);
}
Drawable scrimBg = mContainer.getScrimView().getBackground();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
index 060c71e..8f19444 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -26,8 +26,11 @@
import android.view.View;
import android.view.Window;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.BaseActivity;
import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ScrimView;
@@ -198,4 +201,7 @@
.setOrientationHandler(orientationForLogging))
.build());
}
+
+ @Nullable
+ DesktopVisibilityController getDesktopVisibilityController();
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
similarity index 70%
rename from quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
rename to quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index e8c9718..4604b70 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -16,7 +16,6 @@
package com.android.quickstep.views
-import com.android.quickstep.RecentsAnimationController
import com.android.quickstep.ViewUtils
import com.android.quickstep.recents.viewmodel.RecentsViewModel
import com.android.systemui.shared.recents.model.ThumbnailData
@@ -27,8 +26,8 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
-/** Helper for [RecentsView] to interact with coroutine. */
-class RecentsViewHelper(private val recentsViewModel: RecentsViewModel) {
+/** Helper for [RecentsView] to interact with the [RecentsViewModel]. */
+class RecentsViewModelHelper(private val recentsViewModel: RecentsViewModel) {
private lateinit var viewAttachedScope: CoroutineScope
fun onAttachedToWindow() {
@@ -42,20 +41,8 @@
fun switchToScreenshot(
taskView: TaskView,
- recentsAnimationController: RecentsAnimationController,
- onFinishRunnable: Runnable
- ) {
- val updatedThumbnails =
- taskView.taskContainers.associate {
- it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
- }
- switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable)
- }
-
- fun switchToScreenshot(
- taskView: TaskView,
updatedThumbnails: Map<Int, ThumbnailData>?,
- onFinishRunnable: Runnable
+ onFinishRunnable: Runnable,
) {
// Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside
// viewAttachedScope.
@@ -68,8 +55,4 @@
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/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index af32ba2..13c4f78 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -146,6 +146,7 @@
}
fun bind() {
+ digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition)
if (enableRefactorTaskThumbnail()) {
bindThumbnailView()
} else {
@@ -171,4 +172,19 @@
thumbnailViewDeprecated.setOverlayEnabled(enabled)
}
}
+
+ fun addChildForAccessibility(outChildren: ArrayList<View>) {
+ addAccessibleChildToList(iconView.asView(), outChildren)
+ addAccessibleChildToList(snapshotView, outChildren)
+ showWindowsView?.let { addAccessibleChildToList(it, outChildren) }
+ digitalWellBeingToast?.let { addAccessibleChildToList(it, outChildren) }
+ }
+
+ private fun addAccessibleChildToList(view: View, outChildren: ArrayList<View>) {
+ if (view.includeForAccessibility()) {
+ outChildren.add(view)
+ } else {
+ view.addChildrenForAccessibility(outChildren)
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index 158ae33..19d706f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -99,7 +99,7 @@
private var optionMeasuredHeight = 0
private val arrowHorizontalPadding: Int
get() =
- if (taskView.isFocusedTask)
+ if (taskView.isLargeTile)
resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
else 0
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 176a538..291ccef 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -46,15 +46,14 @@
import androidx.core.view.updateLayoutParams
import com.android.app.animation.Interpolators
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.enableLargeDesktopWindowingTile
import com.android.launcher3.Flags.enableOverviewIconMenu
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.anim.AnimatedFloat
-import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.testing.TestLogging
@@ -64,6 +63,7 @@
import com.android.launcher3.util.Executors
import com.android.launcher3.util.MultiPropertyFactory
import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE
+import com.android.launcher3.util.MultiValueAlpha
import com.android.launcher3.util.RunnableList
import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.SplitConfigurationOptions
@@ -77,7 +77,6 @@
import com.android.launcher3.views.ActivityContext
import com.android.quickstep.RecentsModel
import com.android.quickstep.RemoteAnimationTargets
-import com.android.quickstep.TaskAnimationManager
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.orientation.RecentsPagedOrientationHandler
@@ -108,7 +107,7 @@
defStyleRes: Int = 0,
focusBorderAnimator: BorderAnimator? = null,
hoverBorderAnimator: BorderAnimator? = null,
- type: TaskViewType = TaskViewType.SINGLE
+ private val type: TaskViewType = TaskViewType.SINGLE,
) : FrameLayout(context, attrs), ViewPool.Reusable {
/**
* Used in conjunction with [onTaskListVisibilityChanged], providing more granularity on which
@@ -133,13 +132,15 @@
val isGridTask: Boolean
/** Returns whether the task is part of overview grid and not being focused. */
- get() = container.deviceProfile.isTablet && !isFocusedTask
+ get() = container.deviceProfile.isTablet && !isLargeTile
val isRunningTask: Boolean
get() = this === recentsView?.runningTaskView
- val isFocusedTask: Boolean
- get() = this === recentsView?.focusedTaskView
+ val isLargeTile: Boolean
+ get() =
+ this == recentsView?.focusedTaskView ||
+ (enableLargeDesktopWindowingTile() && type == TaskViewType.DESKTOP)
val taskCornerRadius: Float
get() = currentFullscreenParams.cornerRadius
@@ -198,14 +199,14 @@
get() =
pagedOrientationHandler.getPrimaryValue(
SPLIT_SELECT_TRANSLATION_X,
- SPLIT_SELECT_TRANSLATION_Y
+ SPLIT_SELECT_TRANSLATION_Y,
)
protected val secondarySplitTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getSecondaryValue(
SPLIT_SELECT_TRANSLATION_X,
- SPLIT_SELECT_TRANSLATION_Y
+ SPLIT_SELECT_TRANSLATION_Y,
)
protected val primaryDismissTranslationProperty: FloatProperty<TaskView>
@@ -220,21 +221,21 @@
get() =
pagedOrientationHandler.getPrimaryValue(
TASK_OFFSET_TRANSLATION_X,
- TASK_OFFSET_TRANSLATION_Y
+ TASK_OFFSET_TRANSLATION_Y,
)
protected val secondaryTaskOffsetTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getSecondaryValue(
TASK_OFFSET_TRANSLATION_X,
- TASK_OFFSET_TRANSLATION_Y
+ TASK_OFFSET_TRANSLATION_Y,
)
protected val taskResistanceTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getSecondaryValue(
TASK_RESISTANCE_TRANSLATION_X,
- TASK_RESISTANCE_TRANSLATION_Y
+ TASK_RESISTANCE_TRANSLATION_Y,
)
private val tempCoordinates = FloatArray(2)
@@ -290,9 +291,6 @@
set(value) {
field = value
applyScale()
- if (enableRefactorTaskThumbnail()) {
- taskViewModel.updateNonGridScale(value)
- }
}
private var dismissScale = 1f
@@ -391,14 +389,23 @@
applyTranslationX()
}
- protected var stableAlpha = 1f
+ private val taskViewAlpha = MultiValueAlpha(this, NUM_ALPHA_CHANNELS)
+
+ protected var stableAlpha
set(value) {
- field = value
- alpha = stableAlpha
+ taskViewAlpha.get(ALPHA_INDEX_STABLE).value = value
}
+ get() = taskViewAlpha.get(ALPHA_INDEX_STABLE).value
+
+ protected var attachAlpha
+ set(value) {
+ taskViewAlpha.get(ALPHA_INDEX_ATTACH).value = value
+ }
+ get() = taskViewAlpha.get(ALPHA_INDEX_ATTACH).value
protected var shouldShowScreenshot = false
get() = !isRunningTask || field
+ private set
/** Enable or disable showing border on hover and focus change */
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@@ -426,7 +433,7 @@
field = value
Log.d(
TAG,
- "${taskIds.contentToString()} - setting border animator visibility to: $field"
+ "${taskIds.contentToString()} - setting border animator visibility to: $field",
)
hoverBorderAnimator?.setBorderVisibility(visible = field, animated = true)
}
@@ -446,7 +453,7 @@
FOCUS_TRANSITION,
FOCUS_TRANSITION_INDEX_COUNT,
{ x: Float, y: Float -> x * y },
- 1f
+ 1f,
)
private val focusTransitionFullscreen =
focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_FULLSCREEN)
@@ -477,27 +484,23 @@
taskViewModel = RecentsDependencies.get(this, "TaskViewType" to type)
}
- val keyboardFocusHighlightEnabled =
- (ENABLE_KEYBOARD_QUICK_SWITCH.get() || enableFocusOutline())
val cursorHoverStatesEnabled = enableCursorHoverStates()
- setWillNotDraw(!keyboardFocusHighlightEnabled && !cursorHoverStatesEnabled)
+ setWillNotDraw(!cursorHoverStatesEnabled)
context.obtainStyledAttributes(attrs, R.styleable.TaskView, defStyleAttr, defStyleRes).use {
this.focusBorderAnimator =
focusBorderAnimator
- ?: if (keyboardFocusHighlightEnabled)
- createSimpleBorderAnimator(
- currentFullscreenParams.cornerRadius.toInt(),
- context.resources.getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_border_width
- ),
- { bounds: Rect -> getThumbnailBounds(bounds) },
- this,
- it.getColor(
- R.styleable.TaskView_focusBorderColor,
- BorderAnimator.DEFAULT_BORDER_COLOR
- )
- )
- else null
+ ?: createSimpleBorderAnimator(
+ currentFullscreenParams.cornerRadius.toInt(),
+ context.resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width
+ ),
+ { bounds: Rect -> getThumbnailBounds(bounds) },
+ this,
+ it.getColor(
+ R.styleable.TaskView_focusBorderColor,
+ BorderAnimator.DEFAULT_BORDER_COLOR,
+ ),
+ )
this.hoverBorderAnimator =
hoverBorderAnimator
?: if (cursorHoverStatesEnabled)
@@ -510,8 +513,8 @@
this,
it.getColor(
R.styleable.TaskView_hoverBorderColor,
- BorderAnimator.DEFAULT_BORDER_COLOR
- )
+ BorderAnimator.DEFAULT_BORDER_COLOR,
+ ),
)
else null
}
@@ -521,7 +524,7 @@
public override fun onFocusChanged(
gainFocus: Boolean,
direction: Int,
- previouslyFocusedRect: Rect?
+ previouslyFocusedRect: Rect?,
) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
if (borderEnabled) {
@@ -625,7 +628,7 @@
addAction(
AccessibilityAction(
R.id.action_close,
- context.getText(R.string.accessibility_close)
+ context.getText(R.string.accessibility_close),
)
)
@@ -649,7 +652,7 @@
1,
it.taskViewCount - it.indexOfChild(this@TaskView) - 1,
1,
- false
+ false,
)
}
}
@@ -682,7 +685,7 @@
open fun bind(
task: Task,
orientedState: RecentsOrientedState,
- taskOverlayFactory: TaskOverlayFactory
+ taskOverlayFactory: TaskOverlayFactory,
) {
cancelPendingLoadTasks()
@@ -693,8 +696,9 @@
R.id.snapshot,
R.id.icon,
R.id.show_windows,
+ R.id.digital_wellbeing_toast,
STAGE_POSITION_UNDEFINED,
- taskOverlayFactory
+ taskOverlayFactory,
)
)
taskContainers.forEach { it.bind() }
@@ -706,8 +710,9 @@
@IdRes thumbnailViewId: Int,
@IdRes iconViewId: Int,
@IdRes showWindowViewId: Int,
+ @IdRes digitalWellbeingBannerId: Int,
@StagePosition stagePosition: Int,
- taskOverlayFactory: TaskOverlayFactory
+ taskOverlayFactory: TaskOverlayFactory,
): TaskContainer {
val thumbnailViewDeprecated: TaskThumbnailViewDeprecated = findViewById(thumbnailViewId)!!
val snapshotView =
@@ -721,6 +726,7 @@
thumbnailViewDeprecated
}
val iconView = getOrInflateIconView(iconViewId)
+ val digitalWellBeingToast = findViewById<DigitalWellBeingToast>(digitalWellbeingBannerId)!!
return TaskContainer(
this,
task,
@@ -728,9 +734,9 @@
iconView,
TransformingTouchDelegate(iconView.asView()),
stagePosition,
- DigitalWellBeingToast(container, this),
+ digitalWellBeingToast,
findViewById(showWindowViewId)!!,
- taskOverlayFactory
+ taskOverlayFactory,
)
}
@@ -766,7 +772,7 @@
protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) {
taskContainers.forEach {
it.overlay.updateOrientationState(orientationState)
- it.digitalWellBeingToast?.initialize(it.task)
+ it.digitalWellBeingToast?.initialize()
}
}
@@ -774,10 +780,10 @@
* Updates TaskView scaling and translation required to support variable width if enabled, while
* ensuring TaskView fits into screen in fullscreen.
*/
- fun updateTaskSize(
+ open fun updateTaskSize(
lastComputedTaskSize: Rect,
lastComputedGridTaskSize: Rect,
- lastComputedCarouselTaskSize: Rect
+ lastComputedCarouselTaskSize: Rect,
) {
val thumbnailPadding = container.deviceProfile.overviewTaskThumbnailTopMarginPx
val taskWidth = lastComputedTaskSize.width()
@@ -789,9 +795,10 @@
if (container.deviceProfile.isTablet) {
val boxWidth: Int
val boxHeight: Int
- if (isFocusedTask) {
- // Task will be focused and should use focused task size. Use focusTaskRatio
- // that is associated with the original orientation of the focused task.
+
+ // Focused task and Desktop tasks should use focusTaskRatio that is associated
+ // with the original orientation of the focused task.
+ if (isLargeTile) {
boxWidth = taskWidth
boxHeight = taskHeight
} else {
@@ -817,10 +824,8 @@
} else {
nonGridScale = 1f
boxTranslationY = 0f
- expectedWidth = if (enableOverviewIconMenu()) taskWidth else LayoutParams.MATCH_PARENT
- expectedHeight =
- if (enableOverviewIconMenu()) taskHeight + thumbnailPadding
- else LayoutParams.MATCH_PARENT
+ expectedWidth = taskWidth
+ expectedHeight = taskHeight + thumbnailPadding
}
this.nonGridScale = nonGridScale
this.boxTranslationY = boxTranslationY
@@ -837,6 +842,7 @@
taskContainers[0].snapshotView.updateLayoutParams<LayoutParams> {
topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx
}
+ taskContainers.forEach { it.digitalWellBeingToast?.setupLayout() }
}
/** Returns the thumbnail's bounds, optionally relative to the screen. */
@@ -848,7 +854,7 @@
if (relativeToDragLayer) {
container.dragLayer.getDescendantRectRelativeToSelf(
it.snapshotView,
- thumbnailBounds
+ thumbnailBounds,
)
} else {
thumbnailBounds.set(it.snapshotView)
@@ -929,7 +935,7 @@
if (enableOverviewIconMenu()) {
setText(taskContainer.iconView, taskContainer.task.title)
}
- taskContainer.digitalWellBeingToast?.initialize(taskContainer.task)
+ taskContainer.digitalWellBeingToast?.initialize()
}
protected open fun onIconUnloaded(taskContainer: TaskContainer) {
@@ -964,7 +970,13 @@
iconView.setText(text)
}
- open fun refreshThumbnails(thumbnailDatas: Map<Int, ThumbnailData?>?) {
+ @JvmOverloads
+ open fun setShouldShowScreenshot(
+ shouldShowScreenshot: Boolean,
+ thumbnailDatas: Map<Int, ThumbnailData?>? = null,
+ ) {
+ if (this.shouldShowScreenshot == shouldShowScreenshot) return
+ this.shouldShowScreenshot = shouldShowScreenshot
if (enableRefactorTaskThumbnail()) {
return
}
@@ -985,7 +997,7 @@
return
}
val callbackList =
- launchTasks()?.apply {
+ launchWithAnimation()?.apply {
add {
Log.d("b/310064698", "${taskIds.contentToString()} - onClick - launchCompleted")
}
@@ -997,16 +1009,110 @@
.log(LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP)
}
+ /** Launch of the current task (both live and inactive tasks) with an animation. */
+ fun launchWithAnimation(): RunnableList? {
+ return if (isRunningTask && recentsView?.remoteTargetHandles != null) {
+ launchAsLiveTile()
+ } else {
+ launchAsStaticTile()
+ }
+ }
+
+ private fun launchAsLiveTile(): RunnableList? {
+ val recentsView = recentsView ?: return null
+ val remoteTargetHandles = recentsView.remoteTargetHandles
+ if (!isClickableAsLiveTile) {
+ Log.e(
+ TAG,
+ "launchAsLiveTile - TaskView is not clickable as a live tile; returning to home: ${taskIds.contentToString()}",
+ )
+ return null
+ }
+ isClickableAsLiveTile = false
+ val targets =
+ if (remoteTargetHandles.size == 1) {
+ remoteTargetHandles[0].transformParams.targetSet
+ } else {
+ val apps =
+ remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() }
+ val wallpapers =
+ remoteTargetHandles.flatMap {
+ it.transformParams.targetSet.wallpapers.asIterable()
+ }
+ RemoteAnimationTargets(
+ apps.toTypedArray(),
+ wallpapers.toTypedArray(),
+ remoteTargetHandles[0].transformParams.targetSet.nonApps,
+ remoteTargetHandles[0].transformParams.targetSet.targetMode,
+ )
+ }
+ if (targets == null) {
+ // If the recents animation is cancelled somehow between the parent if block and
+ // here, try to launch the task as a non live tile task.
+ val runnableList = launchAsStaticTile()
+ if (runnableList == null) {
+ Log.e(
+ TAG,
+ "launchAsLiveTile - Recents animation cancelled and cannot launch task as non-live tile; returning to home: ${taskIds.contentToString()}",
+ )
+ }
+ isClickableAsLiveTile = true
+ return runnableList
+ }
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN,
+ "composeRecentsLaunchAnimator",
+ taskIds.contentToString(),
+ )
+ val runnableList = RunnableList()
+ with(AnimatorSet()) {
+ TaskViewUtils.composeRecentsLaunchAnimator(
+ this,
+ this@TaskView,
+ targets.apps,
+ targets.wallpapers,
+ targets.nonApps,
+ true /* launcherClosing */,
+ recentsView.stateManager,
+ recentsView,
+ recentsView.depthController,
+ )
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animator: Animator) {
+ if (taskContainers.any { it.task.key.displayId != rootViewDisplayId }) {
+ launchAsStaticTile()
+ }
+ isClickableAsLiveTile = true
+ runEndCallback()
+ }
+
+ override fun onAnimationCancel(animation: Animator) {
+ runEndCallback()
+ }
+
+ private fun runEndCallback() {
+ runnableList.executeAllAndDestroy()
+ }
+ }
+ )
+ start()
+ }
+ Log.d(TAG, "launchAsLiveTile - composeRecentsLaunchAnimator: ${taskIds.contentToString()}")
+ recentsView.onTaskLaunchedInLiveTileMode()
+ return runnableList
+ }
+
/**
* Starts the task associated with this view and animates the startup.
*
* @return CompletionStage to indicate the animation completion or null if the launch failed.
*/
- open fun launchTaskAnimated(): RunnableList? {
+ open fun launchAsStaticTile(): RunnableList? {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN,
"startActivityFromRecentsAsync",
- taskIds.contentToString()
+ taskIds.contentToString(),
)
val opts =
container.getActivityLaunchOptions(this, null).apply {
@@ -1018,45 +1124,45 @@
) {
Log.d(
TAG,
- "launchTaskAnimated - startActivityFromRecents: ${taskIds.contentToString()}"
+ "launchAsStaticTile - startActivityFromRecents: ${taskIds.contentToString()}",
)
ActiveGestureLog.INSTANCE.trackEvent(
ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED
)
val recentsView = recentsView ?: return null
- if (recentsView.runningTaskViewId != -1) {
+ if (
+ recentsView.runningTaskViewId != -1 &&
+ recentsView.mRecentsAnimationController != null
+ ) {
recentsView.onTaskLaunchedInLiveTileMode()
// Return a fresh callback in the live tile case, so that it's not accidentally
// triggered by QuickstepTransitionManager.AppLaunchAnimationRunner.
return RunnableList().also { recentsView.addSideTaskLaunchCallback(it) }
}
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- // If the recents transition is running (ie. in live tile mode), then the start
- // of a new task will merge into the existing transition and it currently will
- // not be run independently, so we need to rely on the onTaskAppeared() call
- // for the new task to trigger the side launch callback to flush this runnable
- // list (which is usually flushed when the app launch animation finishes)
- recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
- }
+ // If the recents transition is running (ie. in live tile mode), then the start
+ // of a new task will merge into the existing transition and it currently will
+ // not be run independently, so we need to rely on the onTaskAppeared() call
+ // for the new task to trigger the side launch callback to flush this runnable
+ // list (which is usually flushed when the app launch animation finishes)
+ recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
return opts.onEndCallback
} else {
- notifyTaskLaunchFailed()
+ notifyTaskLaunchFailed("launchAsStaticTile")
return null
}
}
/** Starts the task associated with this view without any animation */
- fun launchTask(callback: (launched: Boolean) -> Unit) {
- launchTask(callback, isQuickSwitch = false)
- }
-
- /** Starts the task associated with this view without any animation */
- open fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
+ @JvmOverloads
+ open fun launchWithoutAnimation(
+ isQuickSwitch: Boolean = false,
+ callback: (launched: Boolean) -> Unit,
+ ) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN,
"startActivityFromRecentsAsync",
- taskIds.contentToString()
+ taskIds.contentToString(),
)
val firstContainer = taskContainers[0]
val failureListener = TaskRemovedDuringLaunchListener(context.applicationContext)
@@ -1065,7 +1171,7 @@
// gesture launcher is in the background state, vs other launches which are in
// the actual overview state
failureListener.register(container, firstContainer.task.key.id) {
- notifyTaskLaunchFailed()
+ notifyTaskLaunchFailed("launchWithoutAnimation")
recentsView?.let {
// Disable animations for now, as it is an edge case and the app usually
// covers launcher and also any state transition animation also gets
@@ -1087,7 +1193,7 @@
0,
0,
Executors.MAIN_EXECUTOR.handler,
- { callback(true) }
+ { callback(true) },
) {
failureListener.onTransitionFinished()
}
@@ -1109,103 +1215,20 @@
// otherwise, wait for the animation start callback from the activity options
// above
Executors.MAIN_EXECUTOR.post {
- notifyTaskLaunchFailed()
+ notifyTaskLaunchFailed("launchTask")
callback(false)
}
}
- Log.d(TAG, "launchTask - startActivityFromRecents: ${taskIds.contentToString()}")
+ Log.d(
+ TAG,
+ "launchWithoutAnimation - startActivityFromRecents: ${taskIds.contentToString()}",
+ )
}
}
- /** Launch of the current task (both live and inactive tasks) with an animation. */
- fun launchTasks(): RunnableList? {
- val recentsView = recentsView ?: return null
- val remoteTargetHandles = recentsView.mRemoteTargetHandles
- if (!isRunningTask || remoteTargetHandles == null) {
- return launchTaskAnimated()
- }
- if (!isClickableAsLiveTile) {
- Log.e(TAG, "TaskView is not clickable as a live tile; returning to home.")
- return null
- }
- isClickableAsLiveTile = false
- val targets =
- if (remoteTargetHandles.size == 1) {
- remoteTargetHandles[0].transformParams.targetSet
- } else {
- val apps =
- remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() }
- val wallpapers =
- remoteTargetHandles.flatMap {
- it.transformParams.targetSet.wallpapers.asIterable()
- }
- RemoteAnimationTargets(
- apps.toTypedArray(),
- wallpapers.toTypedArray(),
- remoteTargetHandles[0].transformParams.targetSet.nonApps,
- remoteTargetHandles[0].transformParams.targetSet.targetMode
- )
- }
- if (targets == null) {
- // If the recents animation is cancelled somehow between the parent if block and
- // here, try to launch the task as a non live tile task.
- val runnableList = launchTaskAnimated()
- if (runnableList == null) {
- Log.e(
- TAG,
- "Recents animation cancelled and cannot launch task as non-live tile" +
- "; returning to home"
- )
- }
- isClickableAsLiveTile = true
- return runnableList
- }
- TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN,
- "composeRecentsLaunchAnimator",
- taskIds.contentToString()
- )
- val runnableList = RunnableList()
- with(AnimatorSet()) {
- TaskViewUtils.composeRecentsLaunchAnimator(
- this,
- this@TaskView,
- targets.apps,
- targets.wallpapers,
- targets.nonApps,
- true /* launcherClosing */,
- recentsView.stateManager,
- recentsView,
- recentsView.depthController
- )
- addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animator: Animator) {
- if (taskContainers.any { it.task.key.displayId != rootViewDisplayId }) {
- launchTaskAnimated()
- }
- isClickableAsLiveTile = true
- runEndCallback()
- }
-
- override fun onAnimationCancel(animation: Animator) {
- runEndCallback()
- }
-
- private fun runEndCallback() {
- runnableList.executeAllAndDestroy()
- }
- }
- )
- start()
- }
- Log.d(TAG, "launchTasks - composeRecentsLaunchAnimator: ${taskIds.contentToString()}")
- recentsView.onTaskLaunchedInLiveTileMode()
- return runnableList
- }
-
- private fun notifyTaskLaunchFailed() {
- val sb = StringBuilder("Failed to launch task \n")
+ private fun notifyTaskLaunchFailed(launchMethod: String) {
+ val sb =
+ StringBuilder("$launchMethod - Failed to launch task: ${taskIds.contentToString()}\n")
taskContainers.forEach {
sb.append("(task=${it.task.key.baseIntent} userId=${it.task.key.userId})\n")
}
@@ -1217,7 +1240,7 @@
recentsView?.initiateSplitSelect(
this,
splitPositionOption.stagePosition,
- SplitConfigurationOptions.getLogEventForPosition(splitPositionOption.stagePosition)
+ SplitConfigurationOptions.getLogEventForPosition(splitPositionOption.stagePosition),
)
}
@@ -1240,7 +1263,7 @@
container.splitAnimationThumbnail,
/* intent */ null,
/* user */ null,
- container.itemInfo
+ container.itemInfo,
)
}
@@ -1334,7 +1357,7 @@
private fun computeAndSetIconTouchDelegate(
view: TaskViewIcon,
tempCenterCoordinates: FloatArray,
- transformingTouchDelegate: TransformingTouchDelegate
+ transformingTouchDelegate: TransformingTouchDelegate,
) {
val viewHalfWidth = view.width / 2f
val viewHalfHeight = view.height / 2f
@@ -1345,13 +1368,13 @@
this[0] = viewHalfWidth
this[1] = viewHalfHeight
},
- false
+ false,
)
transformingTouchDelegate.setBounds(
(tempCenterCoordinates[0] - viewHalfWidth).toInt(),
(tempCenterCoordinates[1] - viewHalfHeight).toInt(),
(tempCenterCoordinates[0] + viewHalfWidth).toInt(),
- (tempCenterCoordinates[1] + viewHalfHeight).toInt()
+ (tempCenterCoordinates[1] + viewHalfHeight).toInt(),
)
}
@@ -1361,7 +1384,7 @@
it.showWindowsView?.let { showWindowsView ->
updateFilterCallback(
showWindowsView,
- getFilterUpdateCallback(it.task.key.packageName)
+ getFilterUpdateCallback(it.task.key.packageName),
)
}
}
@@ -1397,7 +1420,7 @@
private fun onFocusTransitionProgressUpdated(focusTransitionProgress: Float) {
taskContainers.forEach {
it.iconView.setContentAlpha(focusTransitionProgress)
- it.digitalWellBeingToast?.updateBannerOffset(1f - focusTransitionProgress)
+ it.digitalWellBeingToast?.bannerOffsetPercentage = 1f - focusTransitionProgress
}
}
@@ -1430,7 +1453,7 @@
it.thumbnailViewDeprecated.dimAlpha = amount
}
it.iconView.setIconColorTint(tintColor, amount)
- it.digitalWellBeingToast?.setBannerColorTint(tintColor, amount)
+ it.digitalWellBeingToast?.setColorTint(tintColor, amount)
}
}
@@ -1444,7 +1467,7 @@
taskContainers.forEach {
if (visibility == VISIBLE || it.task.key.id == taskId) {
it.snapshotView.visibility = visibility
- it.digitalWellBeingToast?.setBannerVisibility(visibility)
+ it.digitalWellBeingToast?.visibility = visibility
it.showWindowsView?.visibility = visibility
it.overlay.setVisibility(visibility)
}
@@ -1547,7 +1570,7 @@
private fun onModalnessUpdated(modalness: Float) {
taskContainers.forEach {
it.iconView.setModalAlpha(1 - modalness)
- it.digitalWellBeingToast?.updateBannerOffset(modalness)
+ it.digitalWellBeingToast?.bannerOffsetPercentage = modalness
}
}
@@ -1583,7 +1606,7 @@
}
dismissScale = 1f
translationZ = 0f
- alpha = stableAlpha
+ attachAlpha = 1f
setIconScaleAndDim(1f)
setColorTint(0f, 0)
}
@@ -1648,6 +1671,12 @@
return thumbnailBounds.contains(x.toInt(), y.toInt())
}
+ override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {
+ (if (isLayoutRtl) taskContainers.reversed() else taskContainers).forEach {
+ it.addChildForAccessibility(outChildren)
+ }
+ }
+
companion object {
private const val TAG = "TaskView"
const val FLAG_UPDATE_ICON = 1
@@ -1660,6 +1689,11 @@
const val FOCUS_TRANSITION_INDEX_SCALE_AND_DIM = 1
const val FOCUS_TRANSITION_INDEX_COUNT = 2
+ private const val ALPHA_INDEX_STABLE = 0
+ private const val ALPHA_INDEX_ATTACH = 1
+
+ private const val NUM_ALPHA_CHANNELS = 2
+
/** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
const val MAX_PAGE_SCRIM_ALPHA = 0.4f
const val SCALE_ICON_DURATION: Long = 120
@@ -1670,7 +1704,7 @@
Interpolators.clampToProgress(
Interpolators.FAST_OUT_SLOW_IN,
1f - FOCUS_TRANSITION_THRESHOLD,
- 1f
+ 1f,
)!!
private val SYSTEM_GESTURE_EXCLUSION_RECT = listOf(Rect())
diff --git a/quickstep/testing/com/android/launcher3/taskbar/bubbles/testing/FakeBubbleViewFactory.kt b/quickstep/testing/com/android/launcher3/taskbar/bubbles/testing/FakeBubbleViewFactory.kt
new file mode 100644
index 0000000..37a07c3
--- /dev/null
+++ b/quickstep/testing/com/android/launcher3/taskbar/bubbles/testing/FakeBubbleViewFactory.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.testing
+
+import android.app.Notification
+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 android.view.ViewGroup
+import com.android.launcher3.R
+import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
+import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.wm.shell.shared.bubbles.BubbleInfo
+
+object FakeBubbleViewFactory {
+
+ /** Inflates a [BubbleView] and adds it to the [parent] view if it is present. */
+ fun createBubble(
+ context: Context,
+ key: String,
+ parent: ViewGroup?,
+ iconSize: Int = 50,
+ iconColor: Int,
+ badgeColor: Int = Color.RED,
+ dotColor: Int = Color.BLUE,
+ suppressNotification: Boolean = false,
+ ): BubbleView {
+ val inflater = LayoutInflater.from(context)
+ // 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 = iconColor)
+ val badge = createCircleBitmap(radius = badgeRadius.toInt(), color = badgeColor)
+
+ val flags =
+ if (suppressNotification) Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION else 0
+ val bubbleInfo =
+ BubbleInfo(key, flags, null, null, 0, context.packageName, null, null, false, true)
+ val bubbleView = inflater.inflate(R.layout.bubblebar_item_view, parent, false) as BubbleView
+ val dotPath =
+ PathParser.createPathFromPathData(
+ context.resources.getString(com.android.internal.R.string.config_icon_mask)
+ )
+ val bubble =
+ BubbleBarBubble(bubbleInfo, bubbleView, badge, icon, dotColor, dotPath, "test app")
+ bubbleView.setBubble(bubble)
+ 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/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewScreenshotTest.kt
new file mode 100644
index 0000000..e4b8069
--- /dev/null
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewScreenshotTest.kt
@@ -0,0 +1,141 @@
+/*
+ * 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.Color
+import android.platform.test.rule.ScreenRecordRule
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.FrameLayout.LayoutParams.MATCH_PARENT
+import android.widget.FrameLayout.LayoutParams.WRAP_CONTENT
+import androidx.activity.ComponentActivity
+import androidx.test.core.app.ApplicationProvider
+import com.android.launcher3.R
+import com.android.launcher3.taskbar.bubbles.testing.FakeBubbleViewFactory
+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 [BubbleBarView]. */
+@RunWith(ParameterizedAndroidJunit4::class)
+@ScreenRecordRule.ScreenRecord
+class BubbleBarViewScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+ private lateinit var bubbleBarView: BubbleBarView
+
+ 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 bubbleBarView_collapsed_oneBubble() {
+ screenshotRule.screenshotTest("bubbleBarView_collapsed_oneBubble") { activity ->
+ activity.actionBar?.hide()
+ setupBubbleBarView()
+ bubbleBarView.addBubble(createBubble("key1", Color.GREEN))
+ val container = FrameLayout(context)
+ val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+ container.layoutParams = lp
+ container.addView(bubbleBarView)
+ container
+ }
+ }
+
+ @Test
+ fun bubbleBarView_collapsed_twoBubbles() {
+ screenshotRule.screenshotTest("bubbleBarView_collapsed_twoBubbles") { activity ->
+ activity.actionBar?.hide()
+ setupBubbleBarView()
+ bubbleBarView.addBubble(createBubble("key1", Color.GREEN))
+ bubbleBarView.addBubble(createBubble("key2", Color.CYAN))
+ val container = FrameLayout(context)
+ val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+ container.layoutParams = lp
+ container.addView(bubbleBarView)
+ container
+ }
+ }
+
+ @Test
+ fun bubbleBarView_expanded_threeBubbles() {
+ // if we're still expanding, wait with taking a screenshot
+ val shouldWait: (ComponentActivity, View) -> Boolean = { _, _ -> bubbleBarView.isExpanding }
+ screenshotRule.screenshotTest(
+ "bubbleBarView_expanded_threeBubbles",
+ checkView = shouldWait,
+ ) { activity ->
+ activity.actionBar?.hide()
+ setupBubbleBarView()
+ bubbleBarView.addBubble(createBubble("key1", Color.GREEN))
+ bubbleBarView.addBubble(createBubble("key2", Color.CYAN))
+ bubbleBarView.addBubble(createBubble("key3", Color.MAGENTA))
+ val container = FrameLayout(context)
+ val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+ container.layoutParams = lp
+ container.addView(bubbleBarView)
+ bubbleBarView.isExpanded = true
+ container
+ }
+ }
+
+ private fun setupBubbleBarView() {
+ bubbleBarView = BubbleBarView(context)
+ val lp = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
+ bubbleBarView.layoutParams = lp
+ val paddingTop =
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_pointer_visible_size)
+ bubbleBarView.setPadding(0, paddingTop, 0, 0)
+ bubbleBarView.visibility = View.VISIBLE
+ bubbleBarView.alpha = 1f
+ }
+
+ private fun createBubble(key: String, color: Int): BubbleView {
+ val bubbleView =
+ FakeBubbleViewFactory.createBubble(
+ context,
+ key,
+ parent = bubbleBarView,
+ iconColor = color,
+ )
+ bubbleView.showDotIfNeeded(1f)
+ bubbleBarView.setSelectedBubble(bubbleView)
+ return bubbleView
+ }
+}
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
index 3e0d6b5..47f393f 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt
@@ -16,15 +16,9 @@
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.android.launcher3.taskbar.bubbles.testing.FakeBubbleViewFactory
import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
import org.junit.Rule
import org.junit.Test
@@ -49,7 +43,7 @@
DeviceEmulationSpec.forDisplays(
Displays.Phone,
isDarkTheme = false,
- isLandscape = false
+ isLandscape = false,
)
}
@@ -57,7 +51,7 @@
val screenshotRule =
ViewScreenshotTestRule(
emulationSpec,
- ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec))
+ ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)),
)
@Test
@@ -72,7 +66,7 @@
fun bubbleView_seen() {
screenshotRule.screenshotTest("bubbleView_seen") { activity ->
activity.actionBar?.hide()
- setupBubbleView().apply { markSeen() }
+ setupBubbleView(suppressNotification = true)
}
}
@@ -84,37 +78,17 @@
}
}
- 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)
+ private fun setupBubbleView(suppressNotification: Boolean = false): BubbleView {
+ val bubbleView =
+ FakeBubbleViewFactory.createBubble(
+ context,
+ key = "key",
+ parent = null,
+ iconSize = 100,
+ iconColor = Color.LTGRAY,
+ suppressNotification = suppressNotification,
)
- 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/TaskbarDesktopModeControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt
new file mode 100644
index 0000000..72bbfc9
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@LauncherMultivalentJUnit.EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+class TaskbarDesktopModeControllerTest {
+
+ private val context =
+ TaskbarWindowSandboxContext.create(
+ InstrumentationRegistry.getInstrumentation().targetContext
+ )
+
+ @get:Rule(order = 0) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @TaskbarUnitTestRule.InjectController
+ lateinit var taskbarDesktopModeController: TaskbarDesktopModeController
+
+ @Test
+ fun whenTaskbarRequiresCornerRoundness_shouldReturnDefaultCornerRoundness() {
+ assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(true))
+ .isEqualTo(MAX_ROUNDNESS)
+ }
+
+ @Test
+ fun whenTaskbarRequiresCornerRoundness_shouldReturnZeroAsCornerRoundness() {
+ assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(false)).isEqualTo(0f)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewControllerTest.kt
new file mode 100644
index 0000000..4aac1dc
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewControllerTest.kt
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.view.View
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.TaskbarViewController.DIVIDER_VIEW_POSITION_OFFSET
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+/**
+ * Legend for the comments below:
+ * A: All Apps Button
+ * H: Hotseat item
+ * |: Divider
+ * R: Recent item
+ *
+ * The comments are formatted in two lines:
+ * // Items in taskbar, e.g. A | HHHHHH
+ * // Index of items relative to Hotseat: -1 -.5 012345
+ */
+class TaskbarViewControllerTest {
+
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+ @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var taskbarViewController: TaskbarViewController
+
+ @Test
+ fun testGetPositionInHotseat_allAppsButton_nonRtl() {
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ 6,
+ /* child = */ View(context),
+ /* isRtl = */ false,
+ /* isAllAppsButton = */ true,
+ /* isTaskbarDividerView = */ false,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ -1
+ )
+ // [>A<] | [HHHHHH]
+ // -1 -.5 012345
+ assertThat(position).isEqualTo(-1)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_allAppsButton_rtl() {
+ val numShownHotseatIcons = 6
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ true,
+ /* isAllAppsButton = */ true,
+ /* isTaskbarDividerView = */ false,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ -1
+ )
+ // [HHHHHH] | [>A<]
+ // 012345 5.5 6
+ assertThat(position).isEqualTo(numShownHotseatIcons)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_dividerView_notForRecents_nonRtl() {
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ 6,
+ /* child = */ View(context),
+ /* isRtl = */ false,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ true,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ -1
+ )
+ // [A] >|< [HHHHHH]
+ // -1 -.5 012345
+ assertThat(position).isEqualTo(-DIVIDER_VIEW_POSITION_OFFSET)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_dividerView_forRecents_nonRtl() {
+ val numShownHotseatIcons = 6
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ false,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ true,
+ /* isDividerForRecents = */ true,
+ /* recentTaskIndex = */ -1
+ )
+ // [A] [HHHHHH] >|< [RR]
+ // -1 012345 5.5 67
+ assertThat(position).isEqualTo(numShownHotseatIcons - DIVIDER_VIEW_POSITION_OFFSET)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_dividerView_notForRecents_rtl() {
+ val numShownHotseatIcons = 6
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ true,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ true,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ -1
+ )
+ // [HHHHHH] >|< [A]
+ // 012345 5.5 6
+ assertThat(position).isEqualTo(numShownHotseatIcons - DIVIDER_VIEW_POSITION_OFFSET)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_dividerView_forRecents_rtl() {
+ val numShownHotseatIcons = 6
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ true,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ true,
+ /* isDividerForRecents = */ true,
+ /* recentTaskIndex = */ -1
+ )
+ // [HHHHHH][A] >|< [RR]
+ // 012345 6 6.5 78
+ assertThat(position).isEqualTo(numShownHotseatIcons + DIVIDER_VIEW_POSITION_OFFSET)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_recentTasks_firstRecentIndex_nonRtl() {
+ val numShownHotseatIcons = 6
+ val recentTaskIndex = 0
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ false,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ false,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ recentTaskIndex
+ )
+ // [A][HHHHHH] | [>R<R]
+ // -1 012345 5.5 6 7
+ assertThat(position).isEqualTo(numShownHotseatIcons + recentTaskIndex)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_recentTasks_secondRecentIndex_nonRtl() {
+ val numShownHotseatIcons = 6
+ val recentTaskIndex = 1
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ false,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ false,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ recentTaskIndex
+ )
+ // [A][HHHHHH] | [R>R<]
+ // -1 012345 5.5 6 7
+ assertThat(position).isEqualTo(numShownHotseatIcons + recentTaskIndex)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_recentTasks_firstRecentIndex_rtl() {
+ val numShownHotseatIcons = 6
+ val recentTaskIndex = 0
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ true,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ false,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ recentTaskIndex
+ )
+ // [HHHHHH][A] | [>R<R]
+ // 012345 6 6.5 7 8
+ assertThat(position).isEqualTo(numShownHotseatIcons + 1 + recentTaskIndex)
+ }
+
+ @Test
+ fun testGetPositionInHotseat_recentTasks_secondRecentIndex_rtl() {
+ val numShownHotseatIcons = 6
+ val recentTaskIndex = 1
+ val position =
+ taskbarViewController.getPositionInHotseat(
+ /* numShownHotseatIcons = */ numShownHotseatIcons,
+ /* child = */ View(context),
+ /* isRtl = */ true,
+ /* isAllAppsButton = */ false,
+ /* isTaskbarDividerView = */ false,
+ /* isDividerForRecents = */ false,
+ /* recentTaskIndex = */ recentTaskIndex
+ )
+ // [HHHHHH][A] | [R>R<]
+ // 012345 6 6.5 7 8
+ assertThat(position).isEqualTo(numShownHotseatIcons + 1 + recentTaskIndex)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt
new file mode 100644
index 0000000..785ec66
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt
@@ -0,0 +1,156 @@
+/*
+ * 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.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
+import com.android.quickstep.inputconsumers.BubbleBarInputConsumer
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+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.any
+import org.mockito.kotlin.whenever
+
+/**
+ * Tests for bubble bar input consumer, namely the static method that indicates whether the input
+ * consumer should handle the event.
+ */
+@RunWith(AndroidJUnit4::class)
+class BubbleBarInputConsumerTest {
+
+ private lateinit var bubbleControllers: BubbleControllers
+
+ @Mock private lateinit var taskbarActivityContext: TaskbarActivityContext
+ @Mock private lateinit var bubbleBarController: BubbleBarController
+ @Mock private lateinit var bubbleBarViewController: BubbleBarViewController
+ @Mock private lateinit var bubbleStashController: BubbleStashController
+ @Mock private lateinit var bubbleStashedHandleViewController: BubbleStashedHandleViewController
+ @Mock private lateinit var bubbleDragController: BubbleDragController
+ @Mock private lateinit var bubbleDismissController: BubbleDismissController
+ @Mock private lateinit var bubbleBarPinController: BubbleBarPinController
+ @Mock private lateinit var bubblePinController: BubblePinController
+ @Mock private lateinit var bubbleCreator: BubbleCreator
+
+ @Mock private lateinit var motionEvent: MotionEvent
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ bubbleControllers =
+ BubbleControllers(
+ bubbleBarController,
+ bubbleBarViewController,
+ bubbleStashController,
+ Optional.of(bubbleStashedHandleViewController),
+ bubbleDragController,
+ bubbleDismissController,
+ bubbleBarPinController,
+ bubblePinController,
+ bubbleCreator
+ )
+ }
+
+ @Test
+ fun testIsEventOnBubbles_noTaskbarActivityContext() {
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(null, motionEvent)).isFalse()
+ }
+
+ @Test
+ fun testIsEventOnBubbles_bubblesNotEnabled() {
+ whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(false)
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+ .isFalse()
+ }
+
+ @Test
+ fun testIsEventOnBubbles_noBubbleControllers() {
+ whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+ whenever(taskbarActivityContext.bubbleControllers).thenReturn(null)
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+ .isFalse()
+ }
+
+ @Test
+ fun testIsEventOnBubbles_noBubbles() {
+ whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+ whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+ .isFalse()
+ }
+
+ @Test
+ fun testIsEventOnBubbles_eventOnStashedHandle() {
+ whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+ whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+ whenever(bubbleStashController.isStashed).thenReturn(true)
+ whenever(bubbleStashedHandleViewController.isEventOverHandle(any())).thenReturn(true)
+
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+ .isTrue()
+ }
+
+ @Test
+ fun testIsEventOnBubbles_eventNotOnStashedHandle() {
+ whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+ whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+ whenever(bubbleStashController.isStashed).thenReturn(true)
+ whenever(bubbleStashedHandleViewController.isEventOverHandle(any())).thenReturn(false)
+
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+ .isFalse()
+ }
+
+ @Test
+ fun testIsEventOnBubbles_eventOnVisibleBubbleView() {
+ whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+ whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+ whenever(bubbleStashController.isStashed).thenReturn(false)
+ whenever(bubbleBarViewController.isBubbleBarVisible).thenReturn(true)
+ whenever(bubbleBarViewController.isEventOverBubbleBar(any())).thenReturn(true)
+
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+ .isTrue()
+ }
+
+ @Test
+ fun testIsEventOnBubbles_eventNotOnVisibleBubbleView() {
+ whenever(taskbarActivityContext.isBubbleBarEnabled).thenReturn(true)
+ whenever(taskbarActivityContext.bubbleControllers).thenReturn(bubbleControllers)
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+ whenever(bubbleStashController.isStashed).thenReturn(false)
+ whenever(bubbleBarViewController.isBubbleBarVisible).thenReturn(true)
+ whenever(bubbleBarViewController.isEventOverBubbleBar(any())).thenReturn(false)
+
+ assertThat(BubbleBarInputConsumer.isEventOnBubbles(taskbarActivityContext, motionEvent))
+ .isFalse()
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
index 8bad3b9..94f9cf5 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewTest.kt
@@ -27,7 +27,7 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.R
-import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.bubbles.BubbleInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,7 +65,7 @@
overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap)
val bubbleInfo =
- BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+ BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false, true)
bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null, false) as BubbleView
bubble =
BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "")
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 21eb3e0..84e872d 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
@@ -37,9 +37,9 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
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
+import com.android.wm.shell.shared.bubbles.BubbleInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -64,6 +64,7 @@
private lateinit var bubble: BubbleBarBubble
private lateinit var bubbleBarView: BubbleBarView
private lateinit var bubbleStashController: BubbleStashController
+ private val onExpandedNoOp = Runnable {}
@Before
fun setUp() {
@@ -81,7 +82,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -98,7 +104,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 +117,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()
}
@@ -125,7 +131,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -142,7 +153,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 +166,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
@@ -168,7 +179,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -179,7 +195,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 +205,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
@@ -208,7 +224,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -230,7 +251,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
@@ -249,7 +270,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -260,12 +286,12 @@
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()
}
@@ -278,8 +304,15 @@
val handleAnimator = PhysicsAnimator.getInstance(handle)
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = true)
@@ -296,13 +329,14 @@
assertThat(bubbleBarView.scaleX).isEqualTo(1)
assertThat(bubbleBarView.scaleY).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.isExpanded).isTrue()
// verify there is no hide animation
assertThat(animatorScheduler.delayedBlock).isNull()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -314,8 +348,15 @@
val handleAnimator = PhysicsAnimator.getInstance(handle)
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -326,7 +367,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()
@@ -344,7 +385,8 @@
assertThat(handle.translationY)
.isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -356,8 +398,15 @@
val handleAnimator = PhysicsAnimator.getInstance(handle)
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -368,7 +417,7 @@
// wait for the animation to end
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -383,7 +432,8 @@
assertThat(handle.translationY)
.isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -400,7 +450,12 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = true, isExpanding = false)
@@ -410,7 +465,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)
@@ -421,7 +476,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)
@@ -442,8 +497,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = true, isExpanding = true)
@@ -453,12 +515,13 @@
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
barAnimator.assertIsNotRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
assertThat(animatorScheduler.delayedBlock).isNull()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -471,7 +534,12 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -481,14 +549,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)
@@ -502,8 +570,15 @@
whenever(bubbleStashController.bubbleBarTranslationY)
.thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -516,7 +591,7 @@
PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(bubbleBarAnimator) { true }
bubbleBarAnimator.assertIsRunning()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -531,8 +606,9 @@
assertThat(animatorScheduler.delayedBlock).isNull()
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -542,8 +618,15 @@
whenever(bubbleStashController.bubbleBarTranslationY)
.thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -553,7 +636,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -565,7 +648,8 @@
assertThat(animatorScheduler.delayedBlock).isNull()
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -578,7 +662,12 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -586,7 +675,7 @@
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 {
@@ -601,7 +690,7 @@
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)
@@ -617,8 +706,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = true)
@@ -626,7 +722,7 @@
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 {
@@ -641,10 +737,11 @@
// verify there is no hide animation
assertThat(animatorScheduler.delayedBlock).isNull()
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(bubbleBarView.isExpanded).isTrue()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -656,8 +753,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -665,7 +769,7 @@
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 {
@@ -679,7 +783,7 @@
// verify there is a pending hide animation
assertThat(animatorScheduler.delayedBlock).isNotNull()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.expandedWhileAnimating()
@@ -691,10 +795,11 @@
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(bubbleBarView.isExpanded).isTrue()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -706,8 +811,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -715,7 +827,7 @@
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 {
@@ -729,7 +841,7 @@
// verify there is a pending hide animation
assertThat(animatorScheduler.delayedBlock).isNotNull()
- assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animator.isAnimating).isTrue()
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.expandedWhileAnimating()
@@ -738,10 +850,11 @@
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
- assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(bubbleBarView.isExpanded).isTrue()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
private fun setUpBubbleBar() {
@@ -757,7 +870,7 @@
bubbleBarView.addView(overflowView)
val bubbleInfo =
- BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
+ BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false, true)
bubbleView =
inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView
bubble =
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index c0a5dfa..4106a2c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -251,7 +251,7 @@
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(translationY)
- whenever(bubbleBarViewController.bubbleBarScale).thenReturn(scale)
+ whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(scale)
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(alpha)
whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index b5809c2..d4a3b3a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar.bubbles.stashing
+import android.animation.AnimatorSet
import android.animation.AnimatorTestRule
import android.content.Context
import android.view.View
@@ -31,7 +32,7 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
-import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.STASHED_BAR_SCALE
+import com.android.launcher3.taskbar.bubbles.BubbleView
import com.android.launcher3.util.MultiValueAlpha
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
@@ -55,11 +56,13 @@
companion object {
const val TASKBAR_BOTTOM_SPACE = 5
- const val BUBBLE_BAR_HEIGHT = 100f
+ const val BUBBLE_BAR_WIDTH = 200
+ const val BUBBLE_BAR_HEIGHT = 100
const val HOTSEAT_TRANSLATION_Y = -45f
const val TASK_BAR_TRANSLATION_Y = -TASKBAR_BOTTOM_SPACE
+ const val HANDLE_VIEW_WIDTH = 150
const val HANDLE_VIEW_HEIGHT = 4
- const val BUBBLE_BAR_STASHED_TRANSLATION_Y = 48
+ const val BUBBLE_BAR_STASHED_TRANSLATION_Y = -4.5f
}
@get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
@@ -75,9 +78,14 @@
private val context = ApplicationProvider.getApplicationContext<Context>()
private lateinit var bubbleBarView: BubbleBarView
private lateinit var stashedHandleView: StashedHandleView
+ private lateinit var bubbleView: BubbleView
private lateinit var barTranslationY: AnimatedFloat
- private lateinit var barScale: AnimatedFloat
+ private lateinit var barScaleX: AnimatedFloat
+ private lateinit var barScaleY: AnimatedFloat
private lateinit var barAlpha: MultiValueAlpha
+ private lateinit var bubbleOffsetY: AnimatedFloat
+ private lateinit var bubbleAlpha: AnimatedFloat
+ private lateinit var backgroundAlpha: AnimatedFloat
private lateinit var stashedHandleAlpha: MultiValueAlpha
private lateinit var stashedHandleScale: AnimatedFloat
private lateinit var stashedHandleTranslationY: AnimatedFloat
@@ -90,7 +98,7 @@
val taskbarHotseatDimensionsProvider =
DefaultDimensionsProvider(taskBarBottomSpace = TASKBAR_BOTTOM_SPACE)
mTransientBubbleStashController =
- TransientBubbleStashController(taskbarHotseatDimensionsProvider, context.resources)
+ TransientBubbleStashController(taskbarHotseatDimensionsProvider, context)
setUpBubbleBarView()
setUpBubbleBarController()
setUpStashedHandleView()
@@ -100,7 +108,7 @@
taskbarInsetsController,
bubbleBarViewController,
bubbleStashedHandleViewController,
- ImmediateAction()
+ ImmediateAction(),
)
}
@@ -156,11 +164,13 @@
mTransientBubbleStashController.isStashed = false
whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+ val bubbleInitialTranslation = bubbleView.translationY
+
// When stash
getInstrumentation().runOnMainSync {
mTransientBubbleStashController.updateStashedAndExpandedState(
stash = true,
- expand = false
+ expand = false,
)
}
@@ -174,11 +184,15 @@
assertThat(mTransientBubbleStashController.isStashed).isTrue()
assertThat(bubbleBarView.translationY).isEqualTo(BUBBLE_BAR_STASHED_TRANSLATION_Y)
assertThat(bubbleBarView.alpha).isEqualTo(0f)
- assertThat(bubbleBarView.scaleX).isEqualTo(STASHED_BAR_SCALE)
- assertThat(bubbleBarView.scaleY).isEqualTo(STASHED_BAR_SCALE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX())
+ assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY())
+ assertThat(bubbleBarView.background.alpha).isEqualTo(255)
// Handle view is visible
assertThat(stashedHandleView.translationY).isEqualTo(0)
assertThat(stashedHandleView.alpha).isEqualTo(1)
+ // Bubble view is reset
+ assertThat(bubbleView.translationY).isEqualTo(bubbleInitialTranslation)
+ assertThat(bubbleView.alpha).isEqualTo(1f)
}
@Test
@@ -196,7 +210,7 @@
// Then
assertThat(barTranslationY.isAnimating).isTrue()
- assertThat(barScale.isAnimating).isTrue()
+ assertThat(barScaleX.isAnimating).isTrue()
// Wait until animation ends
advanceTimeBy(BubbleStashController.BAR_STASH_DURATION)
@@ -243,8 +257,8 @@
// Then all property values are updated
assertThat(bubbleBarView.translationY).isEqualTo(BUBBLE_BAR_STASHED_TRANSLATION_Y)
assertThat(bubbleBarView.alpha).isEqualTo(0)
- assertThat(bubbleBarView.scaleX).isEqualTo(STASHED_BAR_SCALE)
- assertThat(bubbleBarView.scaleY).isEqualTo(STASHED_BAR_SCALE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX())
+ assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY())
// Handle is visible at correct Y position
assertThat(stashedHandleView.alpha).isEqualTo(1)
assertThat(stashedHandleView.translationY).isEqualTo(0)
@@ -269,7 +283,7 @@
val height = mTransientBubbleStashController.getTouchableHeight()
// Then bubble bar height is returned
- assertThat(height).isEqualTo(BUBBLE_BAR_HEIGHT.toInt())
+ assertThat(height).isEqualTo(BUBBLE_BAR_HEIGHT)
}
private fun advanceTimeBy(advanceMs: Long) {
@@ -280,35 +294,46 @@
private fun setUpBubbleBarView() {
getInstrumentation().runOnMainSync {
bubbleBarView = BubbleBarView(context)
- bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0)
+ bubbleBarView.layoutParams =
+ FrameLayout.LayoutParams(BUBBLE_BAR_WIDTH, BUBBLE_BAR_HEIGHT)
+ bubbleView = BubbleView(context)
+ bubbleBarView.addBubble(bubbleView)
+ bubbleBarView.layout(0, 0, BUBBLE_BAR_WIDTH, BUBBLE_BAR_HEIGHT)
}
}
private fun setUpStashedHandleView() {
getInstrumentation().runOnMainSync {
stashedHandleView = StashedHandleView(context)
- stashedHandleView.layoutParams = FrameLayout.LayoutParams(0, 0)
+ stashedHandleView.layoutParams =
+ FrameLayout.LayoutParams(HANDLE_VIEW_WIDTH, HANDLE_VIEW_HEIGHT)
}
}
private fun setUpBubbleBarController() {
barTranslationY =
AnimatedFloat(Runnable { bubbleBarView.translationY = barTranslationY.value })
- barScale =
- AnimatedFloat(
- Runnable {
- val scale: Float = barScale.value
- bubbleBarView.scaleX = scale
- bubbleBarView.scaleY = scale
- }
- )
+ bubbleOffsetY = AnimatedFloat { value -> bubbleBarView.setBubbleOffsetY(value) }
+ barScaleX = AnimatedFloat { value -> bubbleBarView.scaleX = value }
+ barScaleY = AnimatedFloat { value -> bubbleBarView.scaleY = value }
barAlpha = MultiValueAlpha(bubbleBarView, 1 /* num alpha channels */)
+ bubbleAlpha = AnimatedFloat { value -> bubbleBarView.setBubbleAlpha(value) }
+ backgroundAlpha = AnimatedFloat { value -> bubbleBarView.setBackgroundAlpha(value) }
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY)
- whenever(bubbleBarViewController.bubbleBarScale).thenReturn(barScale)
+ whenever(bubbleBarViewController.bubbleOffsetY).thenReturn(bubbleOffsetY)
+ whenever(bubbleBarViewController.bubbleBarBackgroundScaleX).thenReturn(barScaleX)
+ whenever(bubbleBarViewController.bubbleBarBackgroundScaleY).thenReturn(barScaleY)
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
- whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
+ whenever(bubbleBarViewController.bubbleBarBubbleAlpha).thenReturn(bubbleAlpha)
+ whenever(bubbleBarViewController.bubbleBarBackgroundAlpha).thenReturn(backgroundAlpha)
+ whenever(bubbleBarViewController.bubbleBarCollapsedWidth)
+ .thenReturn(BUBBLE_BAR_WIDTH.toFloat())
+ whenever(bubbleBarViewController.bubbleBarCollapsedHeight)
+ .thenReturn(BUBBLE_BAR_HEIGHT.toFloat())
+ whenever(bubbleBarViewController.createRevealAnimatorForStashChange(any()))
+ .thenReturn(AnimatorSet())
}
private fun setUpBubbleStashedHandleViewController() {
@@ -317,7 +342,7 @@
stashedHandleScale =
AnimatedFloat(
Runnable {
- val scale: Float = barScale.value
+ val scale: Float = barScaleX.value
bubbleBarView.scaleX = scale
bubbleBarView.scaleY = scale
}
@@ -327,6 +352,7 @@
whenever(bubbleStashedHandleViewController.stashedHandleAlpha)
.thenReturn(stashedHandleAlpha)
whenever(bubbleStashedHandleViewController.physicsAnimator).thenReturn(stashPhysicsAnimator)
+ whenever(bubbleStashedHandleViewController.stashedWidth).thenReturn(HANDLE_VIEW_WIDTH)
whenever(bubbleStashedHandleViewController.stashedHeight).thenReturn(HANDLE_VIEW_HEIGHT)
whenever(bubbleStashedHandleViewController.setTranslationYForSwipe(any())).thenAnswer {
invocation ->
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/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
index bbcf566..cb5e464 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
@@ -26,6 +26,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ServiceTestRule
import com.android.launcher3.LauncherAppState
+import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks
@@ -143,6 +144,7 @@
PendingIntent(IIntentSender.Default())
},
object : TaskbarNavButtonCallbacks {},
+ DesktopVisibilityController(context),
) {
override fun recreateTaskbar() {
super.recreateTaskbar()
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/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
new file mode 100644
index 0000000..2a0aa4c
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -0,0 +1,276 @@
+/*
+ * 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 static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.ViewTreeObserver;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherRootView;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.util.SystemUiController;
+import com.android.quickstep.util.ActivityInitListener;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.system.InputConsumerController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Collections;
+import java.util.HashMap;
+
+public abstract class AbsSwipeUpHandlerTestCase<
+ RECENTS_CONTAINER extends Context & RecentsViewContainer,
+ STATE extends BaseState<STATE>,
+ RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
+ ACTIVITY_TYPE extends StatefulActivity<STATE> & RecentsViewContainer,
+ ACTIVITY_INTERFACE extends BaseActivityInterface<STATE, ACTIVITY_TYPE>,
+ SWIPE_HANDLER extends AbsSwipeUpHandler<RECENTS_CONTAINER, RECENTS_VIEW, STATE>> {
+
+ protected final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ protected final TaskAnimationManager mTaskAnimationManager = new TaskAnimationManager(mContext);
+ protected final RecentsAnimationDeviceState mRecentsAnimationDeviceState =
+ new RecentsAnimationDeviceState(mContext, true);
+ protected final InputConsumerController mInputConsumerController =
+ InputConsumerController.getRecentsAnimationInputConsumer();
+ protected final ActivityManager.RunningTaskInfo mRunningTaskInfo =
+ new ActivityManager.RunningTaskInfo();
+ protected final TopTaskTracker.CachedTaskInfo mCachedTaskInfo =
+ new TopTaskTracker.CachedTaskInfo(Collections.singletonList(mRunningTaskInfo));
+ protected final RemoteAnimationTarget mRemoteAnimationTarget = new RemoteAnimationTarget(
+ /* taskId= */ 0,
+ /* mode= */ RemoteAnimationTarget.MODE_CLOSING,
+ /* leash= */ new SurfaceControl(),
+ /* isTranslucent= */ false,
+ /* clipRect= */ null,
+ /* contentInsets= */ null,
+ /* prefixOrderIndex= */ 0,
+ /* position= */ null,
+ /* localBounds= */ null,
+ /* screenSpaceBounds= */ null,
+ new Configuration().windowConfiguration,
+ /* isNotInRecents= */ false,
+ /* startLeash= */ null,
+ /* startBounds= */ null,
+ /* taskInfo= */ mRunningTaskInfo,
+ /* allowEnterPip= */ false);
+ protected final RecentsAnimationTargets mRecentsAnimationTargets = new RecentsAnimationTargets(
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ new RemoteAnimationTarget[] {mRemoteAnimationTarget},
+ /* homeContentInsets= */ new Rect(),
+ /* minimizedHomeBounds= */ null,
+ new Bundle());
+
+ @Mock protected ACTIVITY_INTERFACE mActivityInterface;
+ @Mock protected ActivityInitListener<?> mActivityInitListener;
+ @Mock protected RecentsAnimationController mRecentsAnimationController;
+ @Mock protected STATE mState;
+ @Mock protected ViewTreeObserver mViewTreeObserver;
+ @Mock protected DragLayer mDragLayer;
+ @Mock protected LauncherRootView mRootView;
+ @Mock protected SystemUiController mSystemUiController;
+ @Mock protected GestureState mGestureState;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Before
+ public void setUpRunningTaskInfo() {
+ mRunningTaskInfo.baseIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
+ @Before
+ public void setUpGestureState() {
+ when(mGestureState.getRunningTask()).thenReturn(mCachedTaskInfo);
+ when(mGestureState.getLastAppearedTaskIds()).thenReturn(new int[0]);
+ when(mGestureState.getLastStartedTaskIds()).thenReturn(new int[1]);
+ when(mGestureState.getHomeIntent()).thenReturn(new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ doReturn(mActivityInterface).when(mGestureState).getContainerInterface();
+ }
+
+ @Before
+ public void setUpRecentsView() {
+ RECENTS_VIEW recentsView = getRecentsView();
+ when(recentsView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+ doAnswer(answer -> {
+ runOnMainSync(() -> answer.<Runnable>getArgument(0).run());
+ return this;
+ }).when(recentsView).runOnPageScrollsInitialized(any());
+ }
+
+ @Before
+ public void setUpRecentsContainer() {
+ RecentsViewContainer recentsContainer = getRecentsContainer();
+ RECENTS_VIEW recentsView = getRecentsView();
+
+ when(recentsContainer.getDeviceProfile()).thenReturn(new DeviceProfile());
+ when(recentsContainer.getOverviewPanel()).thenReturn(recentsView);
+ when(recentsContainer.getDragLayer()).thenReturn(mDragLayer);
+ when(recentsContainer.getRootView()).thenReturn(mRootView);
+ when(recentsContainer.getSystemUiController()).thenReturn(mSystemUiController);
+ when(mActivityInterface.createActivityInitListener(any()))
+ .thenReturn(mActivityInitListener);
+ doReturn(recentsContainer).when(mActivityInterface).getCreatedContainer();
+ doAnswer(answer -> {
+ answer.<Runnable>getArgument(0).run();
+ return this;
+ }).when(recentsContainer).runOnBindToTouchInteractionService(any());
+ }
+
+ @Test
+ public void testInitWhenReady_registersActivityInitListener() {
+ String reasonString = "because i said so";
+
+ createSwipeHandler().initWhenReady(reasonString);
+ verify(mActivityInitListener).register(eq(reasonString));
+ }
+
+ @Test
+ public void testOnRecentsAnimationCanceled_unregistersActivityInitListener() {
+ createSwipeHandler()
+ .onRecentsAnimationCanceled(new HashMap<>());
+
+ runOnMainSync(() -> verify(mActivityInitListener)
+ .unregister(eq("AbsSwipeUpHandler.onRecentsAnimationCanceled")));
+ }
+
+ @Test
+ public void testOnConsumerAboutToBeSwitched_unregistersActivityInitListener() {
+ createSwipeHandler().onConsumerAboutToBeSwitched();
+
+ runOnMainSync(() -> verify(mActivityInitListener)
+ .unregister("AbsSwipeUpHandler.invalidateHandler"));
+ }
+
+ @Test
+ public void testOnConsumerAboutToBeSwitched_midQuickSwitch_unregistersActivityInitListener() {
+ createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.NEW_TASK)
+ .onConsumerAboutToBeSwitched();
+
+ runOnMainSync(() -> verify(mActivityInitListener)
+ .unregister(eq("AbsSwipeUpHandler.cancelCurrentAnimation")));
+ }
+
+ @Test
+ public void testStartNewTask_finishesRecentsAnimationController() {
+ SWIPE_HANDLER absSwipeUpHandler = createSwipeHandler();
+
+ onRecentsAnimationStart(absSwipeUpHandler);
+
+ runOnMainSync(() -> {
+ absSwipeUpHandler.startNewTask(unused -> {});
+ verify(mRecentsAnimationController).finish(anyBoolean(), any());
+ });
+ }
+
+ @Test
+ public void testHomeGesture_finishesRecentsAnimationController() {
+ createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.HOME);
+
+ runOnMainSync(() -> {
+ verify(mRecentsAnimationController).detachNavigationBarFromApp(true);
+ verify(mRecentsAnimationController).finish(anyBoolean(), any(), anyBoolean());
+ });
+ }
+
+ private SWIPE_HANDLER createSwipeUpHandlerForGesture(GestureState.GestureEndTarget endTarget) {
+ boolean isQuickSwitch = endTarget == GestureState.GestureEndTarget.NEW_TASK;
+
+ doReturn(mState).when(mActivityInterface).stateFromGestureEndTarget(any());
+
+ SWIPE_HANDLER swipeHandler = createSwipeHandler(SystemClock.uptimeMillis(), isQuickSwitch);
+
+ swipeHandler.onActivityInit(/* alreadyOnHome= */ false);
+ swipeHandler.onGestureStarted(isQuickSwitch);
+ onRecentsAnimationStart(swipeHandler);
+
+ when(mGestureState.getRunningTaskIds(anyBoolean())).thenReturn(new int[0]);
+ runOnMainSync(swipeHandler::switchToScreenshot);
+
+ when(mGestureState.getEndTarget()).thenReturn(endTarget);
+ when(mGestureState.isRecentsAnimationRunning()).thenReturn(isQuickSwitch);
+ float xVelocityPxPerMs = isQuickSwitch ? 100 : 0;
+ float yVelocityPxPerMs = isQuickSwitch ? 0 : -100;
+ swipeHandler.onGestureEnded(
+ yVelocityPxPerMs, new PointF(xVelocityPxPerMs, yVelocityPxPerMs));
+ swipeHandler.onCalculateEndTarget();
+ runOnMainSync(swipeHandler::onSettledOnEndTarget);
+
+ return swipeHandler;
+ }
+
+ private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
+ when(mActivityInterface.getOverviewWindowBounds(any(), any())).thenReturn(new Rect());
+ doNothing().when(mActivityInterface).setOnDeferredActivityLaunchCallback(any());
+
+ runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
+ mRecentsAnimationController, mRecentsAnimationTargets));
+ }
+
+ private static void runOnMainSync(Runnable runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+ }
+
+ @NonNull
+ private SWIPE_HANDLER createSwipeHandler() {
+ return createSwipeHandler(SystemClock.uptimeMillis(), false);
+ }
+
+ @NonNull
+ protected abstract SWIPE_HANDLER createSwipeHandler(
+ long touchTimeMs, boolean continuingLastGesture);
+
+ @NonNull
+ protected abstract RecentsViewContainer getRecentsContainer();
+
+ @NonNull
+ protected abstract RECENTS_VIEW getRecentsView();
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
new file mode 100644
index 0000000..dd0b4b3
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.util.LauncherMultivalentJUnit;
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.quickstep.fallback.RecentsState;
+
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
+public class FallbackSwipeHandlerTestCase extends AbsSwipeUpHandlerTestCase<
+ RecentsActivity,
+ RecentsState,
+ FallbackRecentsView,
+ RecentsActivity,
+ FallbackActivityInterface,
+ FallbackSwipeHandler> {
+
+ @Mock private RecentsActivity mRecentsActivity;
+ @Mock private FallbackRecentsView mRecentsView;
+
+
+ @Override
+ protected FallbackSwipeHandler createSwipeHandler(
+ long touchTimeMs, boolean continuingLastGesture) {
+ return new FallbackSwipeHandler(
+ mContext,
+ mRecentsAnimationDeviceState,
+ mTaskAnimationManager,
+ mGestureState,
+ touchTimeMs,
+ continuingLastGesture,
+ mInputConsumerController);
+ }
+
+ @Override
+ protected RecentsActivity getRecentsContainer() {
+ return mRecentsActivity;
+ }
+
+ @Override
+ protected FallbackRecentsView getRecentsView() {
+ return mRecentsView;
+ }
+}
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/LauncherSwipeHandlerV2TestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
new file mode 100644
index 0000000..653dc01
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java
@@ -0,0 +1,92 @@
+/*
+ * 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 static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.WorkspaceStateTransitionAnimation;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.LauncherMultivalentJUnit;
+import com.android.quickstep.views.RecentsView;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
+public class LauncherSwipeHandlerV2TestCase extends AbsSwipeUpHandlerTestCase<
+ QuickstepLauncher,
+ LauncherState,
+ RecentsView<QuickstepLauncher, LauncherState>,
+ QuickstepLauncher,
+ LauncherActivityInterface,
+ LauncherSwipeHandlerV2> {
+
+ @Mock private QuickstepLauncher mQuickstepLauncher;
+ @Mock private RecentsView<QuickstepLauncher, LauncherState> mRecentsView;
+ @Mock private Workspace<?> mWorkspace;
+ @Mock private Hotseat mHotseat;
+ @Mock private WorkspaceStateTransitionAnimation mTransitionAnimation;
+
+ @Before
+ public void setUpQuickStepLauncher() {
+ when(mQuickstepLauncher.createAtomicAnimationFactory())
+ .thenReturn(new AtomicAnimationFactory<>(0));
+ when(mQuickstepLauncher.getHotseat()).thenReturn(mHotseat);
+ doReturn(mWorkspace).when(mQuickstepLauncher).getWorkspace();
+ doReturn(new StateManager(mQuickstepLauncher, LauncherState.NORMAL))
+ .when(mQuickstepLauncher).getStateManager();
+
+ }
+
+ @Before
+ public void setUpWorkspace() {
+ when(mWorkspace.getStateTransitionAnimation()).thenReturn(mTransitionAnimation);
+ }
+
+ @Override
+ protected LauncherSwipeHandlerV2 createSwipeHandler(
+ long touchTimeMs, boolean continuingLastGesture) {
+ return new LauncherSwipeHandlerV2(
+ mContext,
+ mRecentsAnimationDeviceState,
+ mTaskAnimationManager,
+ mGestureState,
+ touchTimeMs,
+ continuingLastGesture,
+ mInputConsumerController);
+ }
+
+ @Override
+ protected QuickstepLauncher getRecentsContainer() {
+ return mQuickstepLauncher;
+ }
+
+ @Override
+ protected RecentsView<QuickstepLauncher, LauncherState> getRecentsView() {
+ return mRecentsView;
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
new file mode 100644
index 0000000..0ae710f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
@@ -0,0 +1,179 @@
+/*
+ * 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.flag.junit.SetFlagsRule
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.TestDispatcherProvider
+import com.android.launcher3.util.rule.setFlags
+import com.android.quickstep.OverviewCommandHelper.CommandInfo
+import com.android.quickstep.OverviewCommandHelper.CommandInfo.CommandStatus
+import com.android.quickstep.OverviewCommandHelper.CommandType
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class OverviewCommandHelperTest {
+ @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule()
+
+ private lateinit var sut: OverviewCommandHelper
+ private val dispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+
+ private var pendingCallbacksWithDelays = mutableListOf<Long>()
+
+ @Suppress("UNCHECKED_CAST")
+ @Before
+ fun setup() {
+ setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_OVERVIEW_COMMAND_HELPER_TIMEOUT)
+
+ sut =
+ spy(
+ OverviewCommandHelper(
+ touchInteractionService = mock(),
+ overviewComponentObserver = mock(),
+ taskAnimationManager = mock(),
+ dispatcherProvider = TestDispatcherProvider(dispatcher)
+ )
+ )
+
+ doAnswer { invocation ->
+ val pendingCallback = invocation.arguments[1] as () -> Unit
+
+ val delayInMillis = pendingCallbacksWithDelays.removeFirstOrNull()
+ if (delayInMillis != null) {
+ runBlocking {
+ testScope.backgroundScope.launch {
+ delay(delayInMillis)
+ pendingCallback.invoke()
+ }
+ }
+ }
+ delayInMillis == null // if no callback to execute, returns success
+ }
+ .`when`(sut)
+ .executeCommand(any<CommandInfo>(), any())
+ }
+
+ private fun addCallbackDelay(delayInMillis: Long = 0) {
+ pendingCallbacksWithDelays.add(delayInMillis)
+ }
+
+ @Test
+ fun whenFirstCommandIsAdded_executeCommandImmediately() =
+ testScope.runTest {
+ // Add command to queue
+ val commandInfo: CommandInfo = sut.addCommand(CommandType.HOME)!!
+ assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE)
+ runCurrent()
+ assertThat(commandInfo.status).isEqualTo(CommandStatus.COMPLETED)
+ }
+
+ @Test
+ fun whenFirstCommandIsAdded_executeCommandImmediately_WithCallbackDelay() =
+ testScope.runTest {
+ addCallbackDelay(100)
+
+ // Add command to queue
+ val commandType = CommandType.HOME
+ val commandInfo: CommandInfo = sut.addCommand(commandType)!!
+ assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE)
+
+ runCurrent()
+ assertThat(commandInfo.status).isEqualTo(CommandStatus.PROCESSING)
+
+ advanceTimeBy(200L)
+ assertThat(commandInfo.status).isEqualTo(CommandStatus.COMPLETED)
+ }
+
+ @Test
+ fun whenFirstCommandIsPendingCallback_NextCommandWillWait() =
+ testScope.runTest {
+ // Add command to queue
+ addCallbackDelay(100)
+ val commandType1 = CommandType.HOME
+ val commandInfo1: CommandInfo = sut.addCommand(commandType1)!!
+ assertThat(commandInfo1.status).isEqualTo(CommandStatus.IDLE)
+
+ addCallbackDelay(100)
+ val commandType2 = CommandType.SHOW
+ val commandInfo2: CommandInfo = sut.addCommand(commandType2)!!
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+ runCurrent()
+ assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING)
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+ advanceTimeBy(101L)
+ assertThat(commandInfo1.status).isEqualTo(CommandStatus.COMPLETED)
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING)
+
+ advanceTimeBy(101L)
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.COMPLETED)
+ }
+
+ @Test
+ fun whenCommandTakesTooLong_TriggerTimeout_AndExecuteNextCommand() =
+ testScope.runTest {
+ // Add command to queue
+ addCallbackDelay(QUEUE_TIMEOUT)
+ val commandType1 = CommandType.HOME
+ val commandInfo1: CommandInfo = sut.addCommand(commandType1)!!
+ assertThat(commandInfo1.status).isEqualTo(CommandStatus.IDLE)
+
+ addCallbackDelay(100)
+ val commandType2 = CommandType.SHOW
+ val commandInfo2: CommandInfo = sut.addCommand(commandType2)!!
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+ runCurrent()
+ assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING)
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
+
+ advanceTimeBy(QUEUE_TIMEOUT)
+ assertThat(commandInfo1.status).isEqualTo(CommandStatus.CANCELED)
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING)
+
+ advanceTimeBy(101)
+ assertThat(commandInfo2.status).isEqualTo(CommandStatus.COMPLETED)
+ }
+
+ private companion object {
+ const val QUEUE_TIMEOUT = 5001L
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
index 80b9489..c18f604 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
@@ -25,6 +25,7 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.quickstep.DeviceConfigWrapper.DEFAULT_LPNH_TIMEOUT_MS;
import static com.google.common.truth.Truth.assertThat;
@@ -39,7 +40,6 @@
import android.os.SystemClock;
import android.view.MotionEvent;
-import android.view.ViewConfiguration;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -142,7 +142,7 @@
@Test
public void testLongPressTriggered() {
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -156,7 +156,7 @@
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE,
-(TOUCH_SLOP - 1)));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -170,7 +170,7 @@
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
mScreenWidth / 2f - (TOUCH_SLOP - 1), 0));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -189,7 +189,7 @@
mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
mScreenWidth / 2f - (TOUCH_SLOP - 1), 0));
// We have entered the second stage, so the normal timeout shouldn't trigger.
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -200,7 +200,7 @@
// After an extended time, the long press should trigger.
float extendedDurationMultiplier =
(DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f);
- SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout()
+ SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS
* (extendedDurationMultiplier - 1))); // -1 because we already waited 1x
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -221,7 +221,7 @@
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
// We have not entered the second stage, so the normal timeout should trigger.
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
@@ -236,7 +236,7 @@
@Test
public void testLongPressAbortedByTouchUp() {
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -256,7 +256,7 @@
@Test
public void testLongPressAbortedByTouchCancel() {
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -276,7 +276,7 @@
@Test
public void testLongPressAbortedByTouchSlopPassedVertically() {
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -297,7 +297,7 @@
@Test
public void testLongPressAbortedByTouchSlopPassedHorizontally() {
mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -326,7 +326,7 @@
mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE,
-(TOUCH_SLOP - 1)));
// Normal duration shouldn't trigger.
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -338,7 +338,7 @@
// Wait past the extended long press timeout, to be sure it wouldn't have triggered.
float extendedDurationMultiplier =
(DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f);
- SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout()
+ SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS
* (extendedDurationMultiplier - 1))); // -1 because we already waited 1x
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -363,7 +363,7 @@
mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
mScreenWidth / 2f - (TOUCH_SLOP - 1), 0));
// Normal duration shouldn't trigger.
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
@@ -375,7 +375,7 @@
// Wait past the extended long press timeout, to be sure it wouldn't have triggered.
float extendedDurationMultiplier =
(DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f);
- SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout()
+ SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS
* (extendedDurationMultiplier - 1))); // -1 because we already waited 1x
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -393,7 +393,7 @@
public void testTouchOutsideNavHandleIgnored() {
// Touch the far left side of the screen. (y=0 is top of navbar region, picked arbitrarily)
mUnderTest.onMotionEvent(generateMotionEvent(ACTION_DOWN, 0, 0));
- SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
// Should be ignored because the x position was not centered in the navbar region.
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 d2479bc..7c48ea4 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -34,9 +34,6 @@
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
@@ -141,7 +138,14 @@
.isTrue()
assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED.id })
.isTrue()
- // LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED
- assertThat(capturedEvents.any { it.id == 617 }).isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED }).isTrue()
+ }
+
+ companion object {
+ private const val KEY_ENABLE_MINUS_ONE = "pref_enable_minus_one"
+ private const val OVERVIEW_SUGGESTED_ACTIONS = "pref_overview_action_suggestions"
+ private const val SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen"
+
+ private const val LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED = 617
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt
new file mode 100644
index 0000000..7d09efd
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+
+class FakeHighResLoadingStateNotifier : HighResLoadingStateNotifier {
+ val listeners = mutableListOf<HighResLoadingStateChangedCallback>()
+
+ override fun addCallback(callback: HighResLoadingStateChangedCallback) {
+ listeners.add(callback)
+ }
+
+ override fun removeCallback(callback: HighResLoadingStateChangedCallback) {
+ listeners.remove(callback)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
index cdfbd16..fc2f029 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
@@ -20,8 +20,6 @@
private var recentsDeviceProfile =
RecentsDeviceProfile(
isLargeScreen = false,
- widthPx = 1080,
- heightPx = 1920,
)
override fun getRecentsDeviceProfile() = recentsDeviceProfile
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
index fee4979..5de876a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
@@ -27,7 +27,8 @@
class FakeTaskIconDataSource : TaskIconDataSource {
- val taskIdToDrawable: Map<Int, Drawable> = (0..10).associateWith { mockCopyableDrawable() }
+ val taskIdToDrawable: MutableMap<Int, Drawable> =
+ (0..10).associateWith { mockCopyableDrawable() }.toMutableMap()
val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
var shouldLoadSynchronously: Boolean = true
@@ -52,15 +53,17 @@
return null
}
- private fun mockCopyableDrawable(): Drawable {
- val mutableDrawable = mock<Drawable>()
- val immutableDrawable =
- mock<Drawable>().apply { whenever(mutate()).thenReturn(mutableDrawable) }
- val constantState =
- mock<Drawable.ConstantState>().apply {
- whenever(newDrawable()).thenReturn(immutableDrawable)
- }
- return mutableDrawable.apply { whenever(this.constantState).thenReturn(constantState) }
+ companion object {
+ fun mockCopyableDrawable(): Drawable {
+ val mutableDrawable = mock<Drawable>()
+ val immutableDrawable =
+ mock<Drawable>().apply { whenever(mutate()).thenReturn(mutableDrawable) }
+ val constantState =
+ mock<Drawable.ConstantState>().apply {
+ whenever(newDrawable()).thenReturn(immutableDrawable)
+ }
+ return mutableDrawable.apply { whenever(this.constantState).thenReturn(constantState) }
+ }
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
index 30fc491..d12c0b0 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
@@ -27,7 +27,8 @@
class FakeTaskThumbnailDataSource : TaskThumbnailDataSource {
- val taskIdToBitmap: Map<Int, Bitmap> = (0..10).associateWith { mock() }
+ val taskIdToBitmap: MutableMap<Int, Bitmap> =
+ (0..10).associateWith { mock<Bitmap>() }.toMutableMap()
val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
var shouldLoadSynchronously: Boolean = true
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt
new file mode 100644
index 0000000..765f0d1
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import com.android.quickstep.util.TaskVisualsChangeListener
+
+class FakeTaskVisualsChangeNotifier : TaskVisualsChangeNotifier {
+ val listeners = mutableListOf<TaskVisualsChangeListener>()
+
+ override fun addThumbnailChangeListener(listener: TaskVisualsChangeListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeThumbnailChangeListener(listener: TaskVisualsChangeListener) {
+ listeners.remove(listener)
+ }
+}
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 d94a351..7a17872 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
@@ -28,7 +28,6 @@
private var taskIconDataMap: Map<Int, TaskIconQueryResponse> = emptyMap()
private var tasks: MutableStateFlow<List<Task>> = MutableStateFlow(emptyList())
private var visibleTasks: MutableStateFlow<List<Int>> = MutableStateFlow(emptyList())
- private var thumbnailOverrideMap: Map<Int, ThumbnailData> = emptyMap()
override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> = tasks
@@ -39,7 +38,7 @@
.map { taskList ->
val task = taskList.firstOrNull { it.key.id == taskId } ?: return@map null
Task(task).apply {
- thumbnail = thumbnailOverrideMap[taskId] ?: task.thumbnail
+ thumbnail = task.thumbnail
icon = task.icon
titleDescription = task.titleDescription
title = task.title
@@ -62,16 +61,6 @@
}
}
}
- setThumbnailOverrideInternal(thumbnailOverrideMap)
- }
-
- override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
- setThumbnailOverrideInternal(thumbnailOverride)
- }
-
- private fun setThumbnailOverrideInternal(thumbnailOverride: Map<Int, ThumbnailData>) {
- thumbnailOverrideMap =
- thumbnailOverride.filterKeys(this.visibleTasks.value::contains).toMap()
}
fun seedTasks(tasks: List<Task>) {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
index e74fe4b..abe4142 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
@@ -39,6 +39,6 @@
whenever(recentsViewContainer.deviceProfile).thenReturn(tabletDeviceProfile)
assertThat(systemUnderTest.getRecentsDeviceProfile())
- .isEqualTo(RecentsDeviceProfile(isLargeScreen = true, widthPx = 1600, heightPx = 2560))
+ .isEqualTo(RecentsDeviceProfile(isLargeScreen = true))
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
new file mode 100644
index 0000000..41f6bfd
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import android.content.ComponentName
+import android.content.Intent
+import android.os.UserHandle
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
+import com.android.systemui.shared.recents.model.Task.TaskKey
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+
+class TaskVisualsChangedDelegateTest {
+ private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier()
+ private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier()
+
+ val systemUnderTest =
+ TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier)
+
+ @Test
+ fun addingFirstListener_addsListenerToNotifiers() {
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+
+ assertThat(taskVisualsChangeNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ assertThat(highResLoadingStateNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ }
+
+ @Test
+ fun addingAndRemovingListener_removesListenerFromNotifiers() {
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+ systemUnderTest.unregisterTaskThumbnailChangedCallback(createTaskKey(id = 1))
+
+ assertThat(taskVisualsChangeNotifier.listeners).isEmpty()
+ assertThat(highResLoadingStateNotifier.listeners).isEmpty()
+ }
+
+ @Test
+ fun addingTwoAndRemovingOneListener_doesNotRemoveListenerFromNotifiers() {
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 2), mock())
+ systemUnderTest.unregisterTaskThumbnailChangedCallback(createTaskKey(id = 1))
+
+ assertThat(taskVisualsChangeNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ assertThat(highResLoadingStateNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ }
+
+ @Test
+ fun onTaskIconChangedWithTaskId_notifiesCorrectListenerOnly() {
+ val expectedListener = mock<TaskIconChangedCallback>()
+ val additionalListener = mock<TaskIconChangedCallback>()
+ systemUnderTest.registerTaskIconChangedCallback(createTaskKey(id = 1), expectedListener)
+ systemUnderTest.registerTaskIconChangedCallback(createTaskKey(id = 2), additionalListener)
+
+ systemUnderTest.onTaskIconChanged(1)
+
+ verify(expectedListener).onTaskIconChanged()
+ verifyNoMoreInteractions(additionalListener)
+ }
+
+ @Test
+ fun onTaskIconChangedWithoutTaskId_notifiesCorrectListenerOnly() {
+ val expectedListener = mock<TaskIconChangedCallback>()
+ val listener = mock<TaskIconChangedCallback>()
+ // Correct match
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+ expectedListener
+ )
+ // 1 out of 2 match
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 2, pkg = PACKAGE_NAME, userId = 1),
+ listener
+ )
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 3, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 2),
+ listener
+ )
+ // 0 out of 2 match
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 4, pkg = PACKAGE_NAME, userId = 2),
+ listener
+ )
+
+ systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
+
+ verify(expectedListener).onTaskIconChanged()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun replacedTaskIconChangedCallbacks_notCalled() {
+ val replacedListener = mock<TaskIconChangedCallback>()
+ val newListener = mock<TaskIconChangedCallback>()
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+ replacedListener
+ )
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+ newListener
+ )
+
+ systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
+
+ verifyNoMoreInteractions(replacedListener)
+ verify(newListener).onTaskIconChanged()
+ }
+
+ @Test
+ fun onTaskThumbnailChanged_notifiesCorrectListenerOnly() {
+ val expectedListener = mock<TaskThumbnailChangedCallback>()
+ val additionalListener = mock<TaskThumbnailChangedCallback>()
+ val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 1),
+ expectedListener
+ )
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 2),
+ additionalListener
+ )
+
+ systemUnderTest.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+ verify(expectedListener).onTaskThumbnailChanged(expectedThumbnailData)
+ verifyNoMoreInteractions(additionalListener)
+ }
+
+ @Test
+ fun onHighResLoadingStateChanged_notifiesAllListeners() {
+ val expectedListener = mock<TaskThumbnailChangedCallback>()
+ val additionalListener = mock<TaskThumbnailChangedCallback>()
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 1),
+ expectedListener
+ )
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 2),
+ additionalListener
+ )
+
+ systemUnderTest.onHighResLoadingStateChanged(true)
+
+ verify(expectedListener).onHighResLoadingStateChanged()
+ verify(additionalListener).onHighResLoadingStateChanged()
+ }
+
+ @Test
+ fun replacedTaskThumbnailChangedCallbacks_notCalled() {
+ val replacedListener1 = mock<TaskThumbnailChangedCallback>()
+ val newListener1 = mock<TaskThumbnailChangedCallback>()
+ val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 1),
+ replacedListener1
+ )
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), newListener1)
+
+ systemUnderTest.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+ verifyNoMoreInteractions(replacedListener1)
+ verify(newListener1).onTaskThumbnailChanged(expectedThumbnailData)
+ }
+
+ private fun createTaskKey(id: Int = 1, pkg: String = PACKAGE_NAME, userId: Int = 1) =
+ TaskKey(id, 0, Intent().setPackage(pkg), ComponentName("", ""), userId, 0)
+
+ private companion object {
+ const val PACKAGE_NAME = "com.test.test"
+ const val ALTERNATIVE_PACKAGE_NAME = "com.test.test2"
+ }
+}
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 b34e156..f31467f 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
@@ -19,7 +19,8 @@
import android.content.ComponentName
import android.content.Intent
import android.graphics.Bitmap
-import android.view.Surface
+import android.graphics.drawable.Drawable
+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,11 @@
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.map
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
@@ -49,233 +51,241 @@
private val recentsModel = FakeRecentTasksDataSource()
private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
private val taskIconDataSource = FakeTaskIconDataSource()
+ private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier()
+ private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier()
+ private val taskVisualsChangedDelegate =
+ TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier)
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(dispatcher)
private val systemUnderTest =
- TasksRepository(recentsModel, taskThumbnailDataSource, taskIconDataSource)
+ TasksRepository(
+ recentsModel,
+ taskThumbnailDataSource,
+ taskIconDataSource,
+ taskVisualsChangedDelegate,
+ 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 addThumbnailOverrideOverrideThumbnails() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val thumbnailOverride2 = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
+ fun getTaskDataByIdReturnsSpecificTask() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
- systemUnderTest.setVisibleTasks(listOf(1, 2))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
-
- // .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(thumbnailOverride2.thumbnail)
- }
+ assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2])
+ }
@Test
- fun addThumbnailOverrideMultipleOverrides() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val thumbnailOverride1 = createThumbnailData()
- val thumbnailOverride2 = createThumbnailData()
- val thumbnailOverride3 = 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.addOrUpdateThumbnailOverride(mapOf(1 to thumbnailOverride1))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride3))
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
- assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride1.thumbnail)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride3.thumbnail)
- }
+ assertThat(systemUnderTest.getTaskDataById(1).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap1)
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
@Test
- fun addThumbnailOverrideClearedWhenTaskBecomeInvisible() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- val thumbnailOverride1 = createThumbnailData()
- val thumbnailOverride2 = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
+ fun setVisibleTasksPopulatesIcons() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ 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))
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
- // .drop(1) to ignore initial null content before from thumbnail was loaded.
- assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride1.thumbnail)
- assertThat(systemUnderTest.getThumbnailById(2).drop(1).first()!!.thumbnail)
- .isEqualTo(bitmap2)
- }
+ systemUnderTest
+ .getTaskDataById(1)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+ systemUnderTest
+ .getTaskDataById(2)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+ }
@Test
- fun addThumbnailOverrideDoesNotOverrideInvisibleTasks() = runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- val thumbnailOverride = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
+ fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
- systemUnderTest.setVisibleTasks(listOf(1))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride))
- 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(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 onTaskThumbnailChanged_setsNewThumbnailDataOnTask() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1))
+
+ val expectedThumbnailData = createThumbnailData()
+ val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
+ val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+ val task1ThumbnailValues = mutableListOf<ThumbnailData?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.thumbnail }.toList(task1ThumbnailValues)
+ }
+ taskVisualsChangedDelegate.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+ assertThat(task1ThumbnailValues[1]!!.thumbnail).isEqualTo(expectedPreviousBitmap)
+ assertThat(task1ThumbnailValues.last()).isEqualTo(expectedThumbnailData)
+ }
+
+ @Test
+ fun onHighResLoadingStateChanged_setsNewThumbnailDataOnTask() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1))
+
+ val expectedBitmap = mock<Bitmap>()
+ val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
+ val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+ val task1ThumbnailValues = mutableListOf<Bitmap?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.thumbnail?.thumbnail }.toList(task1ThumbnailValues)
+ }
+ taskThumbnailDataSource.taskIdToBitmap[1] = expectedBitmap
+ taskVisualsChangedDelegate.onHighResLoadingStateChanged(true)
+
+ assertThat(task1ThumbnailValues[1]).isEqualTo(expectedPreviousBitmap)
+ assertThat(task1ThumbnailValues.last()).isEqualTo(expectedBitmap)
+ }
+
+ @Test
+ fun onTaskIconChanged_setsNewIconOnTask() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1))
+
+ val expectedIcon = FakeTaskIconDataSource.mockCopyableDrawable()
+ val expectedPreviousIcon = taskIconDataSource.taskIdToDrawable[1]
+ val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+ val task1IconValues = mutableListOf<Drawable?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.icon }.toList(task1IconValues)
+ }
+ taskIconDataSource.taskIdToDrawable[1] = expectedIcon
+ taskVisualsChangedDelegate.onTaskIconChanged(1)
+
+ assertThat(task1IconValues[1]).isEqualTo(expectedPreviousIcon)
+ assertThat(task1IconValues.last()).isEqualTo(expectedIcon)
+ }
private fun createTaskWithId(taskId: Int) =
Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000))
- private fun createThumbnailData(rotation: Int = Surface.ROTATION_0): ThumbnailData {
+ private fun createThumbnailData(): ThumbnailData {
val bitmap = mock<Bitmap>()
whenever(bitmap.width).thenReturn(TaskThumbnailViewModelTest.THUMBNAIL_WIDTH)
whenever(bitmap.height).thenReturn(TaskThumbnailViewModelTest.THUMBNAIL_HEIGHT)
- return ThumbnailData(thumbnail = bitmap, rotation = rotation)
+ return ThumbnailData(thumbnail = bitmap)
}
}
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 dc16475..fe67313 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
@@ -70,44 +70,6 @@
assertThat(thumbnailDataFlow2.first()).isNull()
}
- @Test
- fun thumbnailOverrideWaitAndReset() = runTest {
- val thumbnailData1 = createThumbnailData().apply { snapshotId = 1 }
- val thumbnailData2 = createThumbnailData().apply { snapshotId = 2 }
- tasksRepository.seedTasks(tasks)
- tasksRepository.seedThumbnailData(mapOf(1 to thumbnailData1, 2 to thumbnailData2))
-
- val thumbnailDataFlow1 = tasksRepository.getThumbnailById(1)
- val thumbnailDataFlow2 = tasksRepository.getThumbnailById(2)
-
- systemUnderTest.refreshAllTaskData()
- systemUnderTest.updateVisibleTasks(listOf(1, 2))
-
- assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
- assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
-
- systemUnderTest.setRunningTaskShowScreenshot(true)
- val thumbnailOverride = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
- systemUnderTest.addOrUpdateThumbnailOverride(thumbnailOverride)
-
- systemUnderTest.waitForRunningTaskShowScreenshotToUpdate()
- val expectedUpdate = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
- systemUnderTest.waitForThumbnailsToUpdate(expectedUpdate)
-
- assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
- assertThat(thumbnailDataFlow2.first()?.snapshotId).isEqualTo(3)
-
- systemUnderTest.onReset()
-
- assertThat(thumbnailDataFlow1.first()).isNull()
- assertThat(thumbnailDataFlow2.first()).isNull()
-
- systemUnderTest.updateVisibleTasks(listOf(1, 2))
-
- assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
- assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
- }
-
private fun createTaskWithId(taskId: Int) =
Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
colorBackground = Color.argb(taskId, taskId, taskId, taskId)
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCaseTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCaseTest.kt
deleted file mode 100644
index 13e8b09..0000000
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/GetSplashSizeUseCaseTest.kt
+++ /dev/null
@@ -1,84 +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.quickstep.task.thumbnail
-
-import android.graphics.Point
-import android.graphics.drawable.Drawable
-import com.android.quickstep.recents.data.FakeRecentsDeviceProfileRepository
-import com.android.quickstep.task.viewmodel.TaskViewData
-import com.android.quickstep.views.TaskViewType
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.whenever
-
-class GetSplashSizeUseCaseTest {
- private val taskThumbnailViewData = TaskThumbnailViewData()
- private val taskViewData = TaskViewData(TaskViewType.SINGLE)
- private val recentsDeviceProfileRepository = FakeRecentsDeviceProfileRepository()
- private val systemUnderTest =
- GetSplashSizeUseCase(taskThumbnailViewData, taskViewData, recentsDeviceProfileRepository)
-
- @Test
- fun execute_whenNoScaleRequired_returnsIntrinsicSize() {
- taskThumbnailViewData.width.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx
- taskThumbnailViewData.height.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx
-
- assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(100, 100))
- }
-
- @Test
- fun execute_whenThumbnailViewIsSmallerThanScreen_returnsScaledSize() {
- taskThumbnailViewData.width.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx / 2
- taskThumbnailViewData.height.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx / 2
-
- assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(50, 50))
- }
-
- @Test
- fun execute_whenThumbnailViewIsSmallerThanScreen_withNonGridScale_returnsScaledSize() {
- taskThumbnailViewData.width.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx / 2
- taskThumbnailViewData.height.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx / 2
- taskViewData.nonGridScale.value = 2f
-
- assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(25, 25))
- }
-
- @Test
- fun execute_whenThumbnailViewIsSmallerThanScreen_withThumbnailViewScale_returnsScaledSize() {
- taskThumbnailViewData.width.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().widthPx / 2
- taskThumbnailViewData.height.value =
- recentsDeviceProfileRepository.getRecentsDeviceProfile().heightPx / 2
- taskThumbnailViewData.scaleX.value = 2f
- taskThumbnailViewData.scaleY.value = 2f
-
- assertThat(systemUnderTest.execute(createIcon(100, 100))).isEqualTo(Point(25, 25))
- }
-
- private fun createIcon(width: Int, height: Int): Drawable =
- mock<Drawable>().apply {
- whenever(intrinsicWidth).thenReturn(width)
- whenever(intrinsicHeight).thenReturn(height)
- }
-}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
index fe7d37a..fcf4e56 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -21,7 +21,6 @@
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Matrix
-import android.graphics.Point
import android.graphics.drawable.Drawable
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -35,7 +34,6 @@
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.SnapshotSplash
-import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Splash
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskContainerData
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
@@ -46,10 +44,8 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@@ -63,7 +59,6 @@
private val tasksRepository = FakeTasksRepository()
private val mGetThumbnailPositionUseCase = mock<GetThumbnailPositionUseCase>()
private val splashAlphaUseCase: SplashAlphaUseCase = mock()
- private val getSplashSizeUseCase: GetSplashSizeUseCase = mock()
private val systemUnderTest by lazy {
TaskThumbnailViewModel(
recentsViewData,
@@ -72,17 +67,11 @@
tasksRepository,
mGetThumbnailPositionUseCase,
splashAlphaUseCase,
- getSplashSizeUseCase,
)
}
private val tasks = (0..5).map(::createTaskWithId)
- @Before
- fun setUp() {
- whenever(getSplashSizeUseCase.execute(any())).thenReturn(Point())
- }
-
@Test
fun initialStateIsUninitialized() = runTest {
assertThat(systemUnderTest.uiState.first()).isEqualTo(Uninitialized)
@@ -120,7 +109,7 @@
bitmap = expectedThumbnailData.thumbnail!!,
thumbnailRotation = Surface.ROTATION_0,
),
- Splash(expectedIconData.icon, Point())
+ expectedIconData.icon
)
)
}
@@ -215,7 +204,7 @@
bitmap = expectedThumbnailData.thumbnail!!,
thumbnailRotation = Surface.ROTATION_270,
),
- Splash(expectedIconData.icon, Point())
+ expectedIconData.icon
)
)
}
@@ -241,29 +230,12 @@
bitmap = expectedThumbnailData.thumbnail!!,
thumbnailRotation = Surface.ROTATION_0,
),
- Splash(expectedIconData.icon, Point())
+ expectedIconData.icon
)
)
}
@Test
- fun bindStoppedTask_thenStateContainsSplashSizeFromUseCase() = runTest {
- val taskId = 2
- val expectedSplashSize = Point(100, 150)
- whenever(getSplashSizeUseCase.execute(any())).thenReturn(expectedSplashSize)
- val expectedThumbnailData = createThumbnailData(rotation = Surface.ROTATION_270)
- tasksRepository.seedThumbnailData(mapOf(taskId to expectedThumbnailData))
- val expectedIconData = createIconData("Task 2")
- tasksRepository.seedIconData(mapOf(taskId to expectedIconData))
- tasksRepository.seedTasks(tasks)
- tasksRepository.setVisibleTasks(listOf(taskId))
-
- systemUnderTest.bind(taskId)
- val uiState = systemUnderTest.uiState.first() as SnapshotSplash
- assertThat(uiState.splash.size).isEqualTo(expectedSplashSize)
- }
-
- @Test
fun getSnapshotMatrix_MissingThumbnail() = runTest {
val taskId = 2
val isRtl = true
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt
index ece67af..99d3121 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/AppPairsControllerTest.kt
@@ -28,9 +28,9 @@
import com.android.quickstep.TopTaskTracker.CachedTaskInfo
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.Task.TaskKey
-import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_30_70
-import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
-import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_70_30
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_30_70
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_70_30
import java.util.function.Consumer
import org.junit.Assert.assertEquals
import org.junit.Before
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
index f11cd0b..7b1c066 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
@@ -23,7 +23,7 @@
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.views.TaskViewType
import com.android.systemui.shared.recents.model.Task
-import com.android.wm.shell.common.split.SplitScreenConstants
+import com.android.wm.shell.shared.split.SplitScreenConstants
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index f3cde52..5051251 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -27,6 +27,7 @@
import android.window.TransitionInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.apppairs.AppPairIcon
+import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.taskbar.TaskbarActivityContext
@@ -76,6 +77,7 @@
private val splitSelectSource: SplitConfigurationOptions.SplitSelectSource = mock()
private val mockSplitSourceDrawable: Drawable = mock()
private val mockSplitSourceView: View = mock()
+ private val mockItemInfo: ItemInfo = mock()
private val stateManager: StateManager<*, *> = mock()
private val depthController: DepthController = mock()
@@ -89,11 +91,13 @@
whenever(mockTaskContainer.snapshotView).thenReturn(mockSnapshotView)
whenever(mockTaskContainer.splitAnimationThumbnail).thenReturn(mockBitmap)
whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
+ whenever(mockTaskContainer.task).thenReturn(mockTask)
whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
whenever(mockTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
whenever(splitSelectSource.drawable).thenReturn(mockSplitSourceDrawable)
whenever(splitSelectSource.view).thenReturn(mockSplitSourceView)
+ whenever(splitSelectSource.itemInfo).thenReturn(mockItemInfo)
splitAnimationController = SplitAnimationController(mockSplitSelectStateController)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index bab84ef..fc4c4f6 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -39,7 +39,7 @@
import com.android.quickstep.util.SplitSelectStateController.SplitFromDesktopController
import com.android.quickstep.views.RecentsViewContainer
import com.android.systemui.shared.recents.model.Task
-import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50
import java.util.function.Consumer
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
deleted file mode 100644
index 7ef4910..0000000
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
+++ /dev/null
@@ -1,510 +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.quickstep.util;
-
-import static com.android.quickstep.util.TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID;
-import static com.android.quickstep.util.TaskGridNavHelper.INVALID_FOCUSED_TASK_ID;
-
-import static org.junit.Assert.assertEquals;
-
-import com.android.launcher3.util.IntArray;
-
-import org.junit.Test;
-
-public class TaskGridNavHelperTest {
-
- @Test
- public void equalLengthRows_noFocused_onTop_pressDown_goesToBottom() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 1;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 2, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onTop_pressUp_goesToBottom() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 1;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 2, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_pressDown_goesToTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 2;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 1, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_pressUp_goesToTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 2;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 1, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onTop_pressLeft_goesLeft() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 1;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 3, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_pressLeft_goesLeft() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 2;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 4, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onTop_secondItem_pressRight_goesRight() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 3;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 1, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_secondItem_pressRight_goesRight() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 4;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 2, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onTop_pressRight_cycleToClearAll() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 1;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_pressRight_cycleToClearAll() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 2;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onTop_lastItem_pressLeft_toClearAll() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 5;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_lastItem_pressLeft_toClearAll() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 6;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onClearAll_pressLeft_cycleToFirst() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 1, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onClearAll_pressRight_toLastInBottom() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 6, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_withFocused_onFocused_pressLeft_toTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int focusedTaskId = 99;
- int currentPageTaskViewId = focusedTaskId;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 1, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_withFocused_onFocused_pressUp_stayOnFocused() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int focusedTaskId = 99;
- int currentPageTaskViewId = focusedTaskId;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_withFocused_onFocused_pressDown_stayOnFocused() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int focusedTaskId = 99;
- int currentPageTaskViewId = focusedTaskId;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_withFocused_onFocused_pressRight_cycleToClearAll() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int focusedTaskId = 99;
- int currentPageTaskViewId = focusedTaskId;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_withFocused_onClearAll_pressLeft_cycleToFocusedTask() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int focusedTaskId = 99;
- int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, focusedTaskId);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage);
- }
-
- @Test
- public void longerTopRow_noFocused_atEndTopBeyondBottom_pressDown_stayTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5, 7);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 7;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 7, nextGridPage);
- }
-
- @Test
- public void longerTopRow_noFocused_atEndTopBeyondBottom_pressUp_stayTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5, 7);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 7;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 7, nextGridPage);
- }
-
- @Test
- public void longerTopRow_noFocused_atEndBottom_pressLeft_goToTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5, 7);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 6;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 7, nextGridPage);
- }
-
- @Test
- public void longerTopRow_noFocused_atClearAll_pressRight_goToLonger() {
- IntArray topIds = IntArray.wrap(1, 3, 5, 7);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 7, nextGridPage);
- }
-
- @Test
- public void longerBottomRow_noFocused_atClearAll_pressRight_goToLonger() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6, 7);
- int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 7, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onTop_pressTab_goesToBottom() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 1;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 2, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_pressTab_goesToNextTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 2;
- int delta = 1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 3, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onTop_pressTabWithShift_goesToPreviousBottom() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 3;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 2, nextGridPage);
- }
-
- @Test
- public void equalLengthRows_noFocused_onBottom_pressTabWithShift_goesToTop() {
- IntArray topIds = IntArray.wrap(1, 3, 5);
- IntArray bottomIds = IntArray.wrap(2, 4, 6);
- int currentPageTaskViewId = 2;
- int delta = -1;
- @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB;
- boolean cycle = true;
- TaskGridNavHelper taskGridNavHelper =
- new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID);
-
- int nextGridPage =
- taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
-
- assertEquals("Wrong next page returned.", 1, nextGridPage);
- }
-}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.kt
new file mode 100644
index 0000000..7aab75f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.kt
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import com.android.launcher3.util.IntArray
+import com.android.quickstep.util.TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID
+import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_DOWN
+import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_LEFT
+import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_RIGHT
+import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_TAB
+import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_UP
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class TaskGridNavHelperTest {
+
+ /*
+ 5 3 1
+ CLEAR_ALL ↓
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_pressDown_goesToBottom() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_DOWN, delta = 1))
+ .isEqualTo(2)
+ }
+
+ /* ↑----→
+ 5 3 1 |
+ CLEAR_ALL |
+ 6 4 2←---|
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_pressUp_goesToBottom() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_UP, delta = 1)).isEqualTo(2)
+ }
+
+ /* ↓----↑
+ 5 3 1 |
+ CLEAR_ALL |
+ 6 4 2 |
+ ↓----→
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_pressDown_goesToTop() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_DOWN, delta = 1))
+ .isEqualTo(1)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL ↑
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_pressUp_goesToTop() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_UP, delta = 1)).isEqualTo(1)
+ }
+
+ /*
+ 5 3<--1
+ CLEAR_ALL
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_pressLeft_goesLeft() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_LEFT, delta = 1))
+ .isEqualTo(3)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL
+ 6 4<--2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_pressLeft_goesLeft() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_LEFT, delta = 1))
+ .isEqualTo(4)
+ }
+
+ /*
+ 5 3-->1
+ CLEAR_ALL
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_secondItem_pressRight_goesRight() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 3, DIRECTION_RIGHT, delta = -1))
+ .isEqualTo(1)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL
+ 6 4-->2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_secondItem_pressRight_goesRight() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 4, DIRECTION_RIGHT, delta = -1))
+ .isEqualTo(2)
+ }
+
+ /*
+ ↓------------------←
+ | |
+ ↓ 5 3 1---→
+ CLEAR_ALL
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_pressRight_cycleToClearAll() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_RIGHT, delta = -1))
+ .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID)
+ }
+
+ /*
+ ↓------------------←
+ | ↑
+ ↓ 5 3 1 |
+ CLEAR_ALL ↑
+ 6 4 2---→
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_pressRight_cycleToClearAll() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_RIGHT, delta = -1))
+ .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID)
+ }
+
+ /*
+ ←----5 3 1
+ ↓
+ CLEAR_ALL
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_lastItem_pressLeft_toClearAll() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 5, DIRECTION_LEFT, delta = 1))
+ .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL
+ ↑
+ ←---6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_lastItem_pressLeft_toClearAll() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 6, DIRECTION_LEFT, delta = 1))
+ .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID)
+ }
+
+ /*
+ |→-----------------------|
+ | ↓
+ ↑ 5 3 1
+ ←------CLEAR_ALL
+
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onClearAll_pressLeft_cycleToFirst() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID,
+ DIRECTION_LEFT,
+ delta = 1,
+ )
+ )
+ .isEqualTo(1)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL--↓
+ |
+ |--→6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onClearAll_pressRight_toLastInBottom() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID,
+ DIRECTION_RIGHT,
+ delta = -1,
+ )
+ )
+ .isEqualTo(6)
+ }
+
+ /*
+ 5 3 1←---
+ ↑
+ CLEAR_ALL ←--FOCUSED_TASK
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_withFocused_onFocused_pressLeft_toTop() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = FOCUSED_TASK_ID,
+ DIRECTION_LEFT,
+ delta = 1,
+ largeTileIds = listOf(FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(1)
+ }
+
+ /*
+ 5 3 1
+ ←--↑
+ CLEAR_ALL ↓-→FOCUSED_TASK
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_withFocused_onFocused_pressUp_stayOnFocused() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = FOCUSED_TASK_ID,
+ DIRECTION_UP,
+ delta = 1,
+ largeTileIds = listOf(FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(FOCUSED_TASK_ID)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL ↑--→FOCUSED_TASK
+ ↑←--↓
+ 6 4 2
+ */
+
+ @Test
+ fun equalLengthRows_withFocused_onFocused_pressDown_stayOnFocused() {
+
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = FOCUSED_TASK_ID,
+ DIRECTION_DOWN,
+ delta = 1,
+ largeTileIds = listOf(FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(FOCUSED_TASK_ID)
+ }
+
+ /*
+ ↓-------------------------------←|
+ | ↑
+ ↓ 5 3 1 |
+ CLEAR_ALL FOCUSED_TASK--→
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_withFocused_onFocused_pressRight_cycleToClearAll() {
+
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = FOCUSED_TASK_ID,
+ DIRECTION_RIGHT,
+ delta = -1,
+ largeTileIds = listOf(FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID)
+ }
+
+ /*
+ |→---------------------------|
+ | |
+ ↑ 5 3 1 ↓
+ ←------CLEAR_ALL FOCUSED_TASK
+
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_withFocused_onClearAll_pressLeft_cycleToFocusedTask() {
+
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID,
+ DIRECTION_LEFT,
+ delta = 1,
+ largeTileIds = listOf(FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(FOCUSED_TASK_ID)
+ }
+
+ /*
+ 7←-↑ 5 3 1
+ ↓--→
+ CLEAR_ALL
+ 6 4 2
+ */
+ @Test
+ fun longerTopRow_noFocused_atEndTopBeyondBottom_pressDown_stayTop() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = 7,
+ DIRECTION_DOWN,
+ delta = 1,
+ topIds = IntArray.wrap(1, 3, 5, 7),
+ )
+ )
+ .isEqualTo(7)
+ }
+
+ /*
+ ←--↑
+ ↓-→7 5 3 1
+ CLEAR_ALL
+ 6 4 2
+ */
+ @Test
+ fun longerTopRow_noFocused_atEndTopBeyondBottom_pressUp_stayTop() {
+ assertThat(
+ getNextGridPage(
+ /* topIds = */ currentPageTaskViewId = 7,
+ DIRECTION_UP,
+ delta = 1,
+ topIds = IntArray.wrap(1, 3, 5, 7),
+ )
+ )
+ .isEqualTo(7)
+ }
+
+ /*
+ 7 5 3 1
+ CLEAR_ALL ↑
+ ←----6 4 2
+ */
+ @Test
+ fun longerTopRow_noFocused_atEndBottom_pressLeft_goToTop() {
+ assertThat(
+ getNextGridPage(
+ /* topIds = */ currentPageTaskViewId = 6,
+ DIRECTION_LEFT,
+ delta = 1,
+ topIds = IntArray.wrap(1, 3, 5, 7),
+ )
+ )
+ .isEqualTo(7)
+ }
+
+ /*
+ 7 5 3 1
+ ↑
+ CLEAR_ALL-----→
+ 6 4 2
+ */
+ @Test
+ fun longerTopRow_noFocused_atClearAll_pressRight_goToLonger() {
+ assertThat(
+ getNextGridPage(
+ /* topIds = */ currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID,
+ DIRECTION_RIGHT,
+ delta = -1,
+ topIds = IntArray.wrap(1, 3, 5, 7),
+ )
+ )
+ .isEqualTo(7)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL-----→
+ ↓
+ 7 6 4 2
+ */
+ @Test
+ fun longerBottomRow_noFocused_atClearAll_pressRight_goToLonger() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID,
+ DIRECTION_RIGHT,
+ delta = -1,
+ bottomIds = IntArray.wrap(2, 4, 6, 7),
+ )
+ )
+ .isEqualTo(7)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL ↓
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_pressTab_goesToBottom() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_TAB, delta = 1))
+ .isEqualTo(2)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL ↑
+ ←---↑
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_pressTab_goesToNextTop() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_TAB, delta = 1))
+ .isEqualTo(3)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL ↓
+ ----→
+ ↓
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onTop_pressTabWithShift_goesToPreviousBottom() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 3, DIRECTION_TAB, delta = -1))
+ .isEqualTo(2)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL ↑
+ 6 4 2
+ */
+ @Test
+ fun equalLengthRows_noFocused_onBottom_pressTabWithShift_goesToTop() {
+ assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_TAB, delta = -1))
+ .isEqualTo(1)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL FOCUSED_TASK←--DESKTOP
+ 6 4 2
+ */
+ @Test
+ fun withLargeTile_pressLeftFromDesktopTask_goesToFocusedTask() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = DESKTOP_TASK_ID,
+ DIRECTION_LEFT,
+ delta = 1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(FOCUSED_TASK_ID)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL FOCUSED_TASK--→DESKTOP
+ 6 4 2
+ */
+ @Test
+ fun withLargeTile_pressRightFromFocusedTask_goesToDesktopTask() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = FOCUSED_TASK_ID,
+ DIRECTION_RIGHT,
+ delta = -1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(DESKTOP_TASK_ID)
+ }
+
+ /*
+ ↓-----------------------------------------←|
+ | |
+ ↓ 5 3 1 ↑
+ CLEAR_ALL FOCUSED_TASK DESKTOP--→
+ 6 4 2
+ */
+ @Test
+ fun withLargeTile_pressRightFromDesktopTask_goesToClearAll() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = DESKTOP_TASK_ID,
+ DIRECTION_RIGHT,
+ delta = -1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID)
+ }
+
+ /*
+ |→-------------------------------------------|
+ | |
+ ↑ 5 3 1 ↓
+ ←------CLEAR_ALL FOCUSED_TASK DESKTOP
+
+ 6 4 2
+ */
+ @Test
+ fun withLargeTile_pressLeftFromClearAll_goesToDesktopTask() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID,
+ DIRECTION_LEFT,
+ delta = 1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(DESKTOP_TASK_ID)
+ }
+
+ /*
+ 5 3 1
+ CLEAR_ALL FOCUSED_TASK DESKTOP
+ ↑
+ 6 4 2→----↑
+ */
+ @Test
+ fun withLargeTile_pressRightFromBottom_goesToLargeTile() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = 2,
+ DIRECTION_RIGHT,
+ delta = -1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(FOCUSED_TASK_ID)
+ }
+
+ /*
+ 5 3 1→----|
+ ↓
+ CLEAR_ALL FOCUSED_TASK DESKTOP
+ 6 4 2
+ */
+ @Test
+ fun withLargeTile_pressRightFromTop_goesToLargeTile() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = 1,
+ DIRECTION_RIGHT,
+ delta = -1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(FOCUSED_TASK_ID)
+ }
+
+ /*
+ 5 3 1
+
+ CLEAR_ALL FOCUSED_TASK←---DESKTOP
+ 6 4 2
+ */
+ @Test
+ fun withLargeTile_pressTabFromDeskTop_goesToFocusedTask() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = DESKTOP_TASK_ID,
+ DIRECTION_TAB,
+ delta = 1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(FOCUSED_TASK_ID)
+ }
+
+ /*
+ CLEAR_ALL FOCUSED_TASK DESKTOP
+ ↓
+ 2←----↓
+ */
+ @Test
+ fun withLargeTile_pressLeftFromLargeTile_goesToBottom() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = FOCUSED_TASK_ID,
+ DIRECTION_LEFT,
+ delta = 1,
+ topIds = IntArray(),
+ bottomIds = IntArray.wrap(2),
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(2)
+ }
+
+ /*
+ ↓-----------------------------------------←|
+ | |
+ ↓ 5 3 1 ↑
+ CLEAR_ALL FOCUSED_TASK DESKTOP--→
+ 6 4 2
+ */
+ @Test
+ fun withLargeTile_pressShiftTabFromDeskTop_goesToClearAll() {
+ assertThat(
+ getNextGridPage(
+ currentPageTaskViewId = DESKTOP_TASK_ID,
+ DIRECTION_TAB,
+ delta = -1,
+ largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID),
+ )
+ )
+ .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID)
+ }
+
+ private fun getNextGridPage(
+ currentPageTaskViewId: Int,
+ direction: Int,
+ delta: Int,
+ topIds: IntArray = IntArray.wrap(1, 3, 5),
+ bottomIds: IntArray = IntArray.wrap(2, 4, 6),
+ largeTileIds: List<Int> = emptyList(),
+ ): Int {
+ val taskGridNavHelper = TaskGridNavHelper(topIds, bottomIds, largeTileIds)
+ return taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, true)
+ }
+
+ private companion object {
+ const val FOCUSED_TASK_ID = 99
+ const val DESKTOP_TASK_ID = 100
+ }
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 15b1e53..d064f4a 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -57,6 +57,7 @@
@Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
@Mock lateinit var taskbarPinningController: TaskbarPinningController
@Mock lateinit var optionalBubbleControllers: Optional<BubbleControllers>
+ @Mock lateinit var taskbarDesktopModeController: TaskbarDesktopModeController
lateinit var taskbarControllers: TaskbarControllers
@@ -98,6 +99,7 @@
keyboardQuickSwitchController,
taskbarPinningController,
optionalBubbleControllers,
+ taskbarDesktopModeController
)
}
}
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/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 88ffeea..b67bc5a 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -31,7 +31,6 @@
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.TaskItemInfo
-import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.quickstep.RecentsModel
import com.android.quickstep.RecentsModel.RecentTasksChangedListener
import com.android.quickstep.TaskIconCache
@@ -66,9 +65,7 @@
// Update canShowRunningAndRecentAppsAtInit before setUp() is called for each test.
canShowRunningAndRecentAppsAtInit =
description.methodName !in
- listOf(
- "canShowRunningAndRecentAppsAtInitIsFalse_getTasksNeverCalled",
- )
+ listOf("canShowRunningAndRecentAppsAtInitIsFalse_getTasksNeverCalled")
}
}
@@ -76,7 +73,6 @@
@Mock private lateinit var mockRecentsModel: RecentsModel
@Mock private lateinit var mockContext: Context
@Mock private lateinit var mockResources: Resources
- @Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
private var taskListChangeId: Int = 1
@@ -100,13 +96,11 @@
recentTasksChangedListener = null
it
}
- recentAppsController =
- TaskbarRecentAppsController(mockContext, mockRecentsModel) {
- mockDesktopVisibilityController
- }
+ recentAppsController = TaskbarRecentAppsController(mockContext, mockRecentsModel)
recentAppsController.canShowRunningApps = canShowRunningAndRecentAppsAtInit
recentAppsController.canShowRecentApps = canShowRunningAndRecentAppsAtInit
recentAppsController.init(taskbarControllers)
+ taskbarControllers.onPostInit()
recentTasksChangedListener =
if (canShowRunningAndRecentAppsAtInit) {
@@ -133,7 +127,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
runningTasks = listOf(createTask(1, RUNNING_APP_PACKAGE_1)),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
verify(mockRecentsModel, never()).getTasks(any<Consumer<List<GroupTask>>>())
}
@@ -147,7 +141,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
runningTasks = listOf(createTask(1, RUNNING_APP_PACKAGE_1)),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
// Verify that getTasks() was not called again after the init().
verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>())
@@ -162,7 +156,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = hotseatPackages,
runningTasks = emptyList(),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(newHotseatItems.map { it?.targetPackage })
.containsExactlyElementsIn(hotseatPackages)
@@ -177,7 +171,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = hotseatPackages,
runningTasks = emptyList(),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(newHotseatItems.map { it?.targetPackage })
.containsExactlyElementsIn(hotseatPackages)
@@ -191,7 +185,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1),
runningTasks = emptyList(),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val expectedPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
assertThat(newHotseatItems.map { it?.targetPackage })
@@ -206,7 +200,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
runningTasks = listOf(createTask(id = 1, HOTSEAT_PACKAGE_1)),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(newHotseatItems).hasLength(2)
@@ -226,9 +220,9 @@
runningTasks =
listOf(
createTask(id = 1, HOTSEAT_PACKAGE_1),
- createTask(id = 2, HOTSEAT_PACKAGE_1)
+ createTask(id = 2, HOTSEAT_PACKAGE_1),
),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
// First task is in Hotseat Items
@@ -251,7 +245,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1),
runningTasks = emptyList(),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val expectedPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
assertThat(newHotseatItems.map { it?.targetPackage })
@@ -267,9 +261,9 @@
runningTasks =
listOf(
createTask(id = 1, RUNNING_APP_PACKAGE_1),
- createTask(id = 2, RUNNING_APP_PACKAGE_2)
+ createTask(id = 2, RUNNING_APP_PACKAGE_2),
),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(recentAppsController.shownTasks).isEmpty()
}
@@ -281,7 +275,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
assertThat(recentAppsController.shownTasks).isEmpty()
}
@@ -294,9 +288,9 @@
runningTasks =
listOf(
createTask(id = 1, RUNNING_APP_PACKAGE_1),
- createTask(id = 2, RUNNING_APP_PACKAGE_2)
+ createTask(id = 2, RUNNING_APP_PACKAGE_2),
),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(recentAppsController.shownTasks).isEmpty()
assertThat(recentAppsController.minimizedTaskIds).isEmpty()
@@ -308,7 +302,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
assertThat(recentAppsController.shownTasks).isEmpty()
}
@@ -321,7 +315,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val shownTasks = recentAppsController.shownTasks.map { it.task1 }
assertThat(shownTasks).containsExactlyElementsIn(listOf(task1, task2))
@@ -335,7 +329,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(recentAppsController.runningTaskIds).isEmpty()
assertThat(recentAppsController.minimizedTaskIds).isEmpty()
@@ -349,7 +343,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2))
assertThat(recentAppsController.minimizedTaskIds).isEmpty()
@@ -362,12 +356,12 @@
listOf(
createTask(id = 1, HOTSEAT_PACKAGE_1),
createTask(id = 2, RUNNING_APP_PACKAGE_1),
- createTask(id = 3, RUNNING_APP_PACKAGE_2)
+ createTask(id = 3, RUNNING_APP_PACKAGE_2),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
runningTasks = runningTasks,
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2, 3))
assertThat(recentAppsController.minimizedTaskIds).isEmpty()
@@ -383,7 +377,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = runningTasks,
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(recentAppsController.runningTaskIds).containsExactly(1, 2, 3)
assertThat(recentAppsController.minimizedTaskIds).containsExactly(3)
@@ -397,7 +391,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2))
}
@@ -410,13 +404,13 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task2, task1),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val shownTasks = recentAppsController.shownTasks.map { it.task1 }
@@ -431,13 +425,13 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task2, task1),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val shownTasks = recentAppsController.shownTasks.map { it.task1 }
@@ -452,17 +446,17 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(RUNNING_APP_PACKAGE_1),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
updateRecentTasks( // Trigger a recent-tasks change before calling updateHotseatItems()
runningTasks = listOf(task2, task1),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = listOf(RUNNING_APP_PACKAGE_1),
runningTasks = listOf(task2, task1),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val newHotseatItems = recentAppsController.shownHotseatItems
@@ -479,12 +473,12 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1)
+ recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1),
)
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
// Most recent packages, minus the currently running one (RECENT_PACKAGE_1).
@@ -500,12 +494,12 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task2, task1, task3),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
val expectedOrder =
@@ -519,12 +513,12 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_3, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_3, RECENT_PACKAGE_2),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1)
+ recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1),
)
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
// Most recent packages, minus the currently running one (RECENT_PACKAGE_1).
@@ -540,12 +534,12 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1, task2, task3),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task2, task1),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
assertThat(shownPackages).isEqualTo(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
@@ -557,12 +551,12 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3),
)
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3)
+ recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3),
)
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
// Most recent packages, minus the currently running one (RECENT_PACKAGE_3).
@@ -579,7 +573,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(runningTask1, runningTask2),
- recentTaskPackages = recentTaskPackages
+ recentTaskPackages = recentTaskPackages,
)
setInDesktopMode(true)
@@ -597,7 +591,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(runningTask1, runningTask2),
- recentTaskPackages = recentTaskPackages
+ recentTaskPackages = recentTaskPackages,
)
setInDesktopMode(false)
recentTasksChangedListener!!.onRecentTasksChanged()
@@ -613,7 +607,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3),
)
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
// RECENT_PACKAGE_3 is the top task (visible to user) so should be excluded.
@@ -629,7 +623,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(runningTask1, runningTask2),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
val shownPackages = recentAppsController.shownTasks.map { it.packageNames }
// Only 2 recent tasks shown: Desktop Tile + 1 Recent Task
@@ -645,7 +639,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_SPLIT_PACKAGES_1, RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_SPLIT_PACKAGES_1, RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
val shownPackages = recentAppsController.shownTasks.map { it.packageNames }
// Only 2 recent tasks shown: Pair + 1 Recent Task
@@ -661,14 +655,14 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
verify(taskbarViewController, times(1)).commitRunningAppsToUI()
// Call onRecentTasksChanged() again with the same tasks, verify it's a no-op.
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = emptyList(),
- recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
verify(taskbarViewController, times(1)).commitRunningAppsToUI()
}
@@ -681,14 +675,14 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(runningTask1, runningTask2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
verify(taskbarViewController, times(1)).commitRunningAppsToUI()
// Call onRecentTasksChanged() again with the same tasks, verify it's a no-op.
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(runningTask1, runningTask2),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
verify(taskbarViewController, times(1)).commitRunningAppsToUI()
}
@@ -702,7 +696,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1Minimized, task2Visible),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
verify(taskbarViewController, times(1)).commitRunningAppsToUI()
@@ -710,7 +704,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = emptyList(),
runningTasks = listOf(task1Minimized, task2Minimized),
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
verify(taskbarViewController, times(2)).commitRunningAppsToUI()
@@ -726,7 +720,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = hotseatPackages,
runningTasks = originalTasks,
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
verify(taskbarViewController, times(1)).commitRunningAppsToUI()
@@ -734,7 +728,7 @@
prepareHotseatAndRunningAndRecentApps(
hotseatPackages = hotseatPackages,
runningTasks = newTasks,
- recentTaskPackages = emptyList()
+ recentTaskPackages = emptyList(),
)
verify(taskbarViewController, times(2)).commitRunningAppsToUI()
@@ -751,10 +745,7 @@
return recentAppsController.shownHotseatItems.toTypedArray()
}
- private fun updateRecentTasks(
- runningTasks: List<Task>,
- recentTaskPackages: List<String>,
- ) {
+ private fun updateRecentTasks(runningTasks: List<Task>, recentTaskPackages: List<String>) {
val recentTasks = createRecentTasksFromPackageNames(recentTaskPackages)
val allTasks =
ArrayList<GroupTask>().apply {
@@ -790,7 +781,7 @@
private fun createTestAppInfo(
packageName: String = "testPackageName",
- className: String = "testClassName"
+ className: String = "testClassName",
) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent())
private fun createRecentTasksFromPackageNames(packageNames: List<String>): List<GroupTask> {
@@ -800,7 +791,7 @@
GroupTask(
createTask(100, splitPackages[0]),
createTask(101, splitPackages[1]),
- /* splitBounds = */ null
+ /* splitBounds = */ null,
)
} else {
// Use the number at the end of the test packageName as the id.
@@ -818,14 +809,15 @@
Intent().apply { `package` = packageName },
ComponentName(packageName, "TestActivity"),
userHandle.identifier,
- 0
+ 0,
)
)
.apply { this.isVisible = isVisible }
}
private fun setInDesktopMode(inDesktopMode: Boolean) {
- whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode)
+ whenever(taskbarControllers.taskbarDesktopModeController.areDesktopTasksVisible)
+ .thenReturn(inDesktopMode)
}
private val GroupTask.packageNames: List<String>
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index d9d5585..885a7f6 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -39,8 +39,8 @@
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.Task.TaskKey
import com.android.window.flags.Flags
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 2858929..2e456a7 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -248,6 +248,7 @@
}
@Test
+ @ScreenRecordRule.ScreenRecord // b/355042336
public void testOverview() throws IOException {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index cbc8441..244b897 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -39,7 +39,7 @@
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.TaskViewType;
import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import org.junit.Before;
import org.junit.Test;
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 6e25b10..e981570 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -67,15 +67,15 @@
mLauncher.goHome();
final DigitalWellBeingToast toast = getToast();
- waitForLauncherCondition("Toast is not visible", launcher -> toast.hasLimit());
- assertEquals("Toast text: ", "5 minutes left today", toast.getText());
+ waitForLauncherCondition("Toast is not visible", launcher -> toast.getHasLimit());
+ assertEquals("Toast text: ", "5 minutes left today", toast.getBannerText());
// Unset time limit for app.
runWithShellPermission(
() -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
mLauncher.goHome();
- assertFalse("Toast is visible", getToast().hasLimit());
+ assertFalse("Toast is visible", getToast().getHasLimit());
} finally {
runWithShellPermission(
() -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index 2087016..9bc1c59 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -15,20 +15,18 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Intent;
import android.platform.test.annotations.PlatinumTest;
+import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask;
import com.android.launcher3.tapl.OverviewTaskMenu;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.quickstep.util.SplitScreenTestUtils;
import org.junit.Test;
@@ -70,39 +68,17 @@
@Test
public void testSplitTaskTapBothIconMenus() {
- createAndLaunchASplitPair();
+ Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher);
- OverviewTaskMenu taskMenu =
- mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+ OverviewTaskMenu taskMenu = overview.getCurrentTask().tapMenu();
assertTrue("App info item not appearing in expanded task menu.",
taskMenu.hasMenuItem("App info"));
taskMenu.touchOutsideTaskMenuToDismiss();
- OverviewTaskMenu splitMenu =
- mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu(
+ OverviewTaskMenu splitMenu = overview.getCurrentTask().tapMenu(
OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT);
assertTrue("App info item not appearing in expanded split task's menu.",
splitMenu.hasMenuItem("App info"));
splitMenu.touchOutsideTaskMenuToDismiss();
}
-
- private void createAndLaunchASplitPair() {
- clearAllRecentTasks();
-
- startTestActivity(2);
- startTestActivity(3);
-
- if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
- mLauncher.goHome().switchToOverview().getOverviewActions()
- .clickSplit()
- .getTestActivityTask(2)
- .open();
- } else {
- mLauncher.goHome().switchToOverview().getCurrentTask()
- .tapMenu()
- .tapSplitMenuItem()
- .getCurrentTask()
- .open();
- }
- }
-}
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index df73e09..a16811e 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -15,16 +15,12 @@
*/
package com.android.quickstep;
-import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
-
import android.graphics.Rect;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
-import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import org.junit.Assert;
import org.junit.Test;
@@ -35,8 +31,6 @@
public class TaplTestsPersistentTaskbar extends AbstractTaplTestsTaskbar {
@Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- @PortraitLandscape
@NavigationModeSwitch
public void testTaskbarFillsWidth() {
// Width check is performed inside TAPL whenever getTaskbar() is called.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 1dfab26..de2c506 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -266,9 +266,6 @@
return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet();
}
- // Staging; will be promoted to presubmit if stable
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
-
@Test
@NavigationModeSwitch
@PortraitLandscape
@@ -293,9 +290,6 @@
}
}
- // Staging; will be promoted to presubmit if stable
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
-
@Test
@NavigationModeSwitch
@PortraitLandscape
@@ -483,7 +477,8 @@
// assertTrue("Launcher internal state didn't remain in Overview",
// isInState(() -> LauncherState.OVERVIEW));
// overview.getCurrentTask().dismiss();
-// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
+// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple
+// dismissals",
// (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
// launcher)) <= 1)));
@@ -592,7 +587,8 @@
if (overview.hasTasks()) {
currentTask = overview.getCurrentTask();
assertFalse("Found ExcludeFromRecentsTestActivity after entering Overview from Home",
- currentTask.containsContentDescription("ExcludeFromRecents")
+ currentTask.containsContentDescription(
+ "ExcludeFromRecents")
|| currentTask.containsContentDescription(null));
} else {
// Presumably the test started with 0 tasks and remains that way after going home.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 733ea4e..daa4ec3 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -17,8 +17,6 @@
import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -33,7 +31,7 @@
import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.Taskbar;
import com.android.launcher3.tapl.TaskbarAppIcon;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.quickstep.util.SplitScreenTestUtils;
import com.android.wm.shell.Flags;
import org.junit.After;
@@ -110,9 +108,8 @@
assumeTrue("App pairs feature is currently not enabled, no test needed",
Flags.enableAppPairs());
- createAndLaunchASplitPair();
+ Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher);
- Overview overview = mLauncher.goHome().switchToOverview();
if (mLauncher.isGridOnlyOverviewEnabled() || !mLauncher.isTablet()) {
assertTrue("Save app pair menu item is missing",
overview.getCurrentTask()
@@ -156,24 +153,4 @@
TaskbarAppIcon firstApp = taskbar.getAppIcon(firstAppName);
firstApp.launchIntoSplitScreen();
}
-
- private void createAndLaunchASplitPair() {
- clearAllRecentTasks();
-
- startTestActivity(2);
- startTestActivity(3);
-
- if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
- mLauncher.goHome().switchToOverview().getOverviewActions()
- .clickSplit()
- .getTestActivityTask(2)
- .open();
- } else {
- mLauncher.goHome().switchToOverview().getCurrentTask()
- .tapMenu()
- .tapSplitMenuItem()
- .getCurrentTask()
- .open();
- }
- }
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 2c23f86..710ad6f 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -16,8 +16,6 @@
package com.android.quickstep;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
import static org.junit.Assert.assertNotNull;
@@ -32,8 +30,6 @@
import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.ScreenRecordRule;
-import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.After;
@@ -95,8 +91,6 @@
@Test
@PortraitLandscape
@NavigationModeSwitch
- @ScreenRecordRule.ScreenRecord // b/336606166
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/336606166
public void switchToOverview() throws Exception {
assumeTrue(mLauncher.isTablet());
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 3a83ae3..28c8a4a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -59,8 +59,6 @@
@Test
public void startRecentsActivity_allowBackgroundLaunch() {
- assumeTrue(TaskAnimationManager.ENABLE_SHELL_TRANSITIONS);
-
final LauncherActivityInterface activityInterface = mock(LauncherActivityInterface.class);
final GestureState gestureState = mock(GestureState.class);
final RecentsAnimationCallbacks.RecentsAnimationListener listener =
diff --git a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
index 4d10f0f..cb59f7d 100644
--- a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
@@ -55,7 +55,6 @@
private val taskbarDragLayer = mock<TaskbarDragLayer>()
private val taskbarSharedState = mock<TaskbarSharedState>()
private var isInDesktopMode = false
- private val isInDesktopModeProvider = { isInDesktopMode }
private val launcherPrefs =
mock<LauncherPrefs> {
on { get(TASKBAR_PINNING) } doReturn false
@@ -71,8 +70,9 @@
whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs)
whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer)
whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager)
- pinningController =
- spy(TaskbarPinningController(taskbarActivityContext, isInDesktopModeProvider))
+ whenever(taskbarControllers.taskbarDesktopModeController.areDesktopTasksVisible)
+ .thenAnswer { _ -> isInDesktopMode }
+ pinningController = spy(TaskbarPinningController(taskbarActivityContext))
pinningController.init(taskbarControllers, taskbarSharedState)
}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
new file mode 100644
index 0000000..82361aa
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import androidx.test.uiautomator.By
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.launcher3.tapl.Overview
+import com.android.launcher3.tapl.OverviewTask
+import com.android.launcher3.ui.AbstractLauncherUiTest
+
+object SplitScreenTestUtils {
+
+ /** Creates 2 tasks and makes a split mode pair. Also asserts the accessibility labels. */
+ @JvmStatic
+ fun createAndLaunchASplitPairInOverview(launcher: LauncherInstrumentation): Overview {
+ clearAllRecentTasks(launcher)
+
+ AbstractLauncherUiTest.startTestActivity(2)
+ AbstractLauncherUiTest.startTestActivity(3)
+
+ val overView = launcher.goHome().switchToOverview()
+ if (launcher.isTablet && !launcher.isGridOnlyOverviewEnabled) {
+ overView.overviewActions.clickSplit().getTestActivityTask(2).open()
+ } else {
+ overView.currentTask.tapMenu().tapSplitMenuItem().currentTask.open()
+ }
+
+ val overviewWithSplitPair = launcher.goHome().switchToOverview()
+ val currentTask = overviewWithSplitPair.currentTask
+ currentTask.containsContentDescription(
+ By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity3").toString(),
+ OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT
+ )
+ currentTask.containsContentDescription(
+ By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity2").toString(),
+ OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT
+ )
+ return overviewWithSplitPair
+ }
+
+ private fun clearAllRecentTasks(launcher: LauncherInstrumentation) {
+ if (launcher.recentTasks.isNotEmpty()) {
+ launcher.goHome().switchToOverview().dismissAllTasks()
+ }
+ }
+}
diff --git a/res/color-night-v31/popup_color_background.xml b/res/color-night-v31/popup_color_background.xml
deleted file mode 100644
index 13ceaa0..0000000
--- a/res/color-night-v31/popup_color_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item
- android:color="@android:color/system_neutral1_900"
- android:lStar="12" />
-</selector>
diff --git a/res/color-v31/popup_color_background.xml b/res/color-v31/popup_color_background.xml
deleted file mode 100644
index 99155d8..0000000
--- a/res/color-v31/popup_color_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item
- android:color="@android:color/system_neutral1_50"
- android:lStar="94" />
-</selector>
diff --git a/res/color/popup_color_background.xml b/res/color/popup_color_background.xml
deleted file mode 100644
index e87e772..0000000
--- a/res/color/popup_color_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:color="?attr/popupColorBackground" />
-</selector>
diff --git a/res/drawable/add_item_dialog_background.xml b/res/drawable/add_item_dialog_background.xml
index be4765a..39af989 100644
--- a/res/drawable/add_item_dialog_background.xml
+++ b/res/drawable/add_item_dialog_background.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
- <solid android:color="?attr/materialColorSurfaceContainerHighest" />
+ <solid android:color="?attr/widgetPickerPrimarySurfaceColor" />
<corners
android:topLeftRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="?android:attr/dialogCornerRadius" />
diff --git a/res/drawable/bg_letter_list_text.xml b/res/drawable/bg_letter_list_text.xml
new file mode 100644
index 0000000..427702b
--- /dev/null
+++ b/res/drawable/bg_letter_list_text.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="?attr/materialColorSurfaceContainer" />
+ <corners android:radius="100dp"/>
+ <size
+ android:width="@dimen/bg_letter_list_text_size"
+ android:height="@dimen/bg_letter_list_text_size"/>
+</shape>
\ 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/popup_background.xml b/res/drawable/popup_background.xml
index 6eedecb..4ddd228 100644
--- a/res/drawable/popup_background.xml
+++ b/res/drawable/popup_background.xml
@@ -15,6 +15,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?attr/popupColorBackground"/>
+ <solid android:color="?attr/materialColorSurfaceContainer"/>
<corners android:radius="@dimen/dialogCornerRadius"/>
</shape>
\ No newline at end of file
diff --git a/res/drawable/widget_picker_tabs_background.xml b/res/drawable/widget_picker_tabs_background.xml
index a874dd8..f6607b7 100644
--- a/res/drawable/widget_picker_tabs_background.xml
+++ b/res/drawable/widget_picker_tabs_background.xml
@@ -13,36 +13,39 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/accent_ripple_color">
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetBottom="@dimen/widget_apps_tabs_vertical_padding"
+ android:insetTop="@dimen/widget_apps_tabs_vertical_padding">
+ <ripple
+ android:color="@color/accent_ripple_color">
- <item android:id="@android:id/mask">
- <shape android:shape="rectangle">
- <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- <solid android:color="@color/accent_ripple_color" />
- </shape>
- </item>
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+ <solid android:color="@color/accent_ripple_color" />
+ </shape>
+ </item>
- <item>
- <selector android:enterFadeDuration="100">
- <item
- android:id="@+id/unselected"
- android:state_selected="false">
- <shape android:shape="rectangle">
- <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- <solid android:color="?attr/widgetPickerTabBackgroundUnselected"/>
- </shape>
- </item>
+ <item>
+ <selector android:enterFadeDuration="100">
+ <item
+ android:id="@+id/unselected"
+ android:state_selected="false">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+ <solid android:color="?attr/widgetPickerTabBackgroundUnselected" />
+ </shape>
+ </item>
- <item
- android:id="@+id/selected"
- android:state_selected="true">
- <shape android:shape="rectangle">
- <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- <solid android:color="?attr/widgetPickerTabBackgroundSelected"/>
- </shape>
- </item>
- </selector>
- </item>
-
-</ripple>
\ No newline at end of file
+ <item
+ android:id="@+id/selected"
+ android:state_selected="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+ <solid android:color="?attr/widgetPickerTabBackgroundSelected" />
+ </shape>
+ </item>
+ </selector>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 0f1d933..7e16ca5 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -36,4 +36,17 @@
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/scroll_letter_layout"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/all_apps_header"
+ android:layout_marginTop="@dimen/all_apps_header_bottom_padding"
+ android:layout_marginEnd="@dimen/fastscroll_list_letter_end_margin"
+ android:clipToPadding="false"
+ android:outlineProvider="none"
+ />
</merge>
\ No newline at end of file
diff --git a/res/layout/fast_scroller_letter_list_text_view.xml b/res/layout/fast_scroller_letter_list_text_view.xml
new file mode 100644
index 0000000..493b6fc
--- /dev/null
+++ b/res/layout/fast_scroller_letter_list_text_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<com.android.launcher3.allapps.LetterListTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/fastscroll_list_letter_size"
+ android:layout_height="@dimen/fastscroll_list_letter_size"
+ android:textSize="@dimen/fastscroll_list_letter_text_size"
+ android:importantForAccessibility="no"
+ android:gravity="center"
+ android:clickable="false">
+</com.android.launcher3.allapps.LetterListTextView>
\ No newline at end of file
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index a709fbc..83c8d6c 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -51,7 +51,7 @@
<!-- Keep these behind the workspace so that they are not visible when
we go into AllApps -->
- <com.android.launcher3.pageindicators.WorkspacePageIndicator
+ <com.android.launcher3.pageindicators.PageIndicatorDots
android:id="@+id/page_indicator"
android:layout_width="match_parent"
android:layout_height="@dimen/workspace_page_indicator_height"
diff --git a/res/layout/page_indicator_dots.xml b/res/layout/page_indicator_dots.xml
deleted file mode 100644
index d5fe51e..0000000
--- a/res/layout/page_indicator_dots.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.launcher3.pageindicators.PageIndicatorDots xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/page_indicator"
- android:layout_width="match_parent"
- android:layout_height="@dimen/workspace_page_indicator_height"
- android:layout_gravity="bottom | center_horizontal"
- android:theme="@style/HomeScreenElementTheme" />
\ No newline at end of file
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/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 8dc785a..622f0d6 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -104,7 +104,6 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
- android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
android:layout_weight="1"
android:background="@drawable/widget_picker_tabs_background"
android:text="@string/widgets_full_sheet_personal_tab"
@@ -117,7 +116,6 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
- android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
android:layout_weight="1"
android:background="@drawable/widget_picker_tabs_background"
android:text="@string/widgets_full_sheet_work_tab"
diff --git a/res/layout/widgets_two_pane_sheet_paged_view.xml b/res/layout/widgets_two_pane_sheet_paged_view.xml
index 1f41680..1cbd2ba 100644
--- a/res/layout/widgets_two_pane_sheet_paged_view.xml
+++ b/res/layout/widgets_two_pane_sheet_paged_view.xml
@@ -115,7 +115,6 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
- android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
android:layout_weight="1"
android:background="@drawable/widget_picker_tabs_background"
android:text="@string/widgets_full_sheet_personal_tab"
@@ -128,7 +127,6 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
- android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
android:layout_weight="1"
android:background="@drawable/widget_picker_tabs_background"
android:text="@string/widgets_full_sheet_work_tab"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index dca7cab..490a7c2 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Borrel"</string>
<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..7292eec 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ጫን"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"መተግበሪያውን አይጠቁሙ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"የፒን ግምት"</string>
+ <string name="bubble" msgid="3072951361014076670">"አረፋ"</string>
<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..06fc0a8 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"تثبيت"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"عدم اقتراح التطبيق"</string>
<string name="pin_prediction" msgid="4196423321649756498">"تثبيت التطبيق المتوقّع"</string>
+ <string name="bubble" msgid="3072951361014076670">"فقاعة"</string>
<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..cd6e347 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনষ্টল কৰক"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"পৰামৰ্শ নিদিব"</string>
<string name="pin_prediction" msgid="4196423321649756498">"পূৰ্বানুমান কৰা এপ্টো পিন কৰক"</string>
+ <string name="bubble" msgid="3072951361014076670">"বাবল"</string>
<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..b8d660f 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Qabarcıq"</string>
<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..4d4764e 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
<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..641509e 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string>
+ <string name="bubble" msgid="3072951361014076670">"Бурбалка"</string>
<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..3ce3c5f 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталиране"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Без предлагане на приложение"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Фиксиране на предвиждането"</string>
+ <string name="bubble" msgid="3072951361014076670">"Балонче"</string>
<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..9b23590 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
<string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
+ <string name="bubble" msgid="3072951361014076670">"বাবল"</string>
<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..4a34da7 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
<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..c341ec7 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bombolla"</string>
<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..d3512c9 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bublat"</string>
<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..8aae860 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Boble"</string>
<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..374f5a1 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
<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..cafe86e 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
+ <string name="bubble" msgid="3072951361014076670">"Συννεφάκι"</string>
<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..1b0722d 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/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-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..1b0722d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/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-rIN/strings.xml b/res/values-en-rIN/strings.xml
index c9579a5..1b0722d 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/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-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..ba1b0af 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Burbuja"</string>
<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..ad12192 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Burbuja"</string>
<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..96d0b2c 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Mull"</string>
<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..bc9b8c1 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Burbuila"</string>
<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..c167194 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -24,7 +24,7 @@
<string name="activity_not_found" msgid="8071924732094499514">"برنامه نصب نشده است."</string>
<string name="activity_not_available" msgid="7456344436509528827">"برنامه در دسترس نیست"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"برنامه بارگیری شده در حالت ایمن غیرفعال شد"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"ابزارکها در حالت ایمن غیرفعال هستند"</string>
+ <string name="safemode_widget_error" msgid="4863470563535682004">"ابزارهها در حالت ایمن غیرفعال هستند"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"میانبر دردسترس نیست"</string>
<string name="home_screen" msgid="5629429142036709174">"صفحه اصلی"</string>
<string name="set_default_home_app" msgid="5808906607627586381">"تنظیم <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> بهعنوان برنامه صفحه اصلی پیشفرض در «تنظیمات»"</string>
@@ -36,40 +36,40 @@
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"از این جفت برنامه در این دستگاه پشتیبانی نمیشود"</string>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"برای استفاده از این جفت برنامه، دستگاه را باز کنید"</string>
<string name="app_pair_not_available" msgid="3556767440808032031">"جفت برنامه دردسترس نیست"</string>
- <string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابهجا کردن ابزارک، لمس کنید و نگه دارید."</string>
- <string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابهجا کردن ابزارک یا استفاده از کنشهای سفارشی، دو تکضرب بزنید و نگه دارید."</string>
+ <string name="long_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_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>
- <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>، %2$d عرض در %3$d ارتفاع"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ابزارک را لمس کنید و نگه دارید تا بتوانید آن را در صفحه اصلی حرکت دهید"</string>
+ <string name="widget_preview_context_description" msgid="9045841361655787574">"ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+ <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>، %2$d عرض در %3$d ارتفاع"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ابزاره را لمس کنید و نگه دارید تا بتوانید آن را در صفحه اصلی حرکت دهید"</string>
<string name="add_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="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>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهاداتی برای شما"</string>
- <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزارکهای <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، جستجو و گزینهها در سمت راست"</string>
- <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ابزارک}one{# ابزارک}other{# ابزارک}}"</string>
+ <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزارههای <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، «جستجو» و گزینهها در سمت راست"</string>
+ <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ابزاره}one{# ابزاره}other{# ابزاره}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# میانبر}one{# میانبر}other{# میانبر}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>،<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ابزارکها"</string>
+ <string name="widget_button_text" msgid="2880537293434387943">"ابزارهها"</string>
<string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"جستجو"</string>
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"پاک کردن نوشتار از چارگوش جستجو"</string>
- <string name="no_widgets_available" msgid="4337693382501046170">"ابزارک و میانبری دردسترس نیست"</string>
- <string name="no_search_results" msgid="3787956167293097509">"هیچ ابزارک یا میانبری پیدا نشد"</string>
- <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ابزارکهای شخصی"</string>
- <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"کار"</string>
+ <string name="no_widgets_available" msgid="4337693382501046170">"ابزاره و میانبری دردسترس نیست"</string>
+ <string name="no_search_results" msgid="3787956167293097509">"هیچ ابزاره یا میانبری پیدا نشد"</string>
+ <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ابزارههای شخصی"</string>
+ <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ابزارههای کاری"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"مکالمهها"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"یادداشتبرداری"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"افزودن"</string>
- <string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزارک، تکضرب بزنید"</string>
- <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغییر تنظیمات ابزارک"</string>
+ <string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+ <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزاره، تکضرب بزنید"</string>
+ <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغییر تنظیمات ابزاره"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"جستجوی برنامهها"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"درحال بارگیری برنامهها…"</string>
<string name="all_apps_no_search_results" msgid="3200346862396363786">"هیچ برنامهای در مطابقت با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
@@ -92,14 +92,15 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"نصب"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"برنامه پیشنهاد داده نشود"</string>
<string name="pin_prediction" msgid="4196423321649756498">"سنجاق کردن پیشنهاد"</string>
+ <string name="bubble" msgid="3072951361014076670">"حبابک"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"نصب میانبرها"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"به برنامه اجازه میدهد میانبرها را بدون دخالت کاربر اضافه کند."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"خواندن تنظیمات و میانبرهای صفحه اصلی"</string>
<string name="permdesc_read_settings" msgid="4208061150510996676">"به برنامه اجازه میدهد تنظیمات و میانبرهای صفحه اصلی را بخواند."</string>
<string name="permlab_write_settings" msgid="4820028712156303762">"نوشتن تنظیمات و میانبرهای صفحه اصلی"</string>
<string name="permdesc_write_settings" msgid="726859348127868466">"به برنامه اجازه میدهد تنظیمات و میانبرهای صفحه اصلی را تغییر دهد."</string>
- <string name="gadget_error_text" msgid="740356548025791839">"ابزارک را نمیتوان بار کرد"</string>
- <string name="gadget_setup_text" msgid="8348374825537681407">"تنظیمات ابزارک"</string>
+ <string name="gadget_error_text" msgid="740356548025791839">"ابزاره را نمیتوان بار کرد"</string>
+ <string name="gadget_setup_text" msgid="8348374825537681407">"تنظیمات ابزاره"</string>
<string name="gadget_complete_setup_text" msgid="309040266978007925">"برای تکمیل راهاندازی تکضرب بزنید"</string>
<string name="uninstall_system_app_text" msgid="4172046090762920660">"این برنامه سیستمی است و حذف نصب نمیشود."</string>
<string name="folder_hint_text" msgid="5174843001373488816">"ویرایش نام"</string>
@@ -145,8 +146,8 @@
<string name="dialog_update_message" msgid="4176784553982226114">"برنامه برای این نماد بهروز نشده است. میتوانید آن را بهصورت دستی بهروز کنید تا میانبر دوباره فعال شود، یا نماد را بردارید."</string>
<string name="dialog_update" msgid="2178028071796141234">"بهروزرسانی"</string>
<string name="dialog_remove" msgid="6510806469849709407">"برداشتن"</string>
- <string name="widgets_list" msgid="796804551140113767">"فهرست ابزارکها"</string>
- <string name="widgets_list_closed" msgid="6141506579418771922">"فهرست ابزارکها بسته شد"</string>
+ <string name="widgets_list" msgid="796804551140113767">"فهرست ابزارهها"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"فهرست ابزارهها بسته شد"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"افزودن به صفحه اصلی"</string>
<string name="action_move_here" msgid="2170188780612570250">"انتقال مورد به اینجا"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"مورد به صفحه اصلی اضافه شد"</string>
@@ -168,7 +169,7 @@
<string name="action_increase_height" msgid="459390020612501122">"افزایش ارتفاع"</string>
<string name="action_decrease_width" msgid="1374549771083094654">"کاهش عرض"</string>
<string name="action_decrease_height" msgid="282377193880900022">"کاهش ارتفاع"</string>
- <string name="widget_resized" msgid="9130327887929620">"اندازه ابزارک به عرض <xliff:g id="NUMBER_0">%1$s</xliff:g> ارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g> تغییر کرد"</string>
+ <string name="widget_resized" msgid="9130327887929620">"اندازه ابزاره به عرض <xliff:g id="NUMBER_0">%1$s</xliff:g> ارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g> تغییر کرد"</string>
<string name="action_deep_shortcut" msgid="2864038805849372848">"میانبرها"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"رد کردن"</string>
<string name="accessibility_close" msgid="2277148124685870734">"بستن"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 9eaaeb6..007d077 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Kupla"</string>
<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..c443505 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bulle"</string>
<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..4f5d111 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -31,7 +31,7 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
- <string name="save_app_pair" msgid="5647523853662686243">"Enregistrer la paire d\'applis"</string>
+ <string name="save_app_pair" msgid="5647523853662686243">"Enregistrer une paire d\'applis"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Dépliez l\'appareil pour utiliser cette paire d\'applications"</string>
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bulle"</string>
<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..ff7c029 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Burbulla"</string>
<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..872faef 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
<string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
+ <string name="bubble" msgid="3072951361014076670">"બબલ"</string>
<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..a44b874 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करें"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ऐप्लिकेशन का सुझाव न दें"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सुझाए गए ऐप पिन करें"</string>
+ <string name="bubble" msgid="3072951361014076670">"बबल"</string>
<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..d9f2072 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
<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..6bc8b70 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Buborék"</string>
<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..69b320d 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
+ <string name="bubble" msgid="3072951361014076670">"Ամպիկ"</string>
<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..58a429f 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Balon"</string>
<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..95bd21f 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Blaðra"</string>
<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..3c01cd4 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Fumetto"</string>
<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..f198166 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -63,7 +63,7 @@
<string name="no_widgets_available" msgid="4337693382501046170">"אין ווידג\'טים או קיצורי דרך"</string>
<string name="no_search_results" msgid="3787956167293097509">"לא נמצאו ווידג\'טים או קיצורי דרך"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ווידג\'טים אישיים"</string>
- <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"עבודה"</string>
+ <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ווידג\'טים לעבודה"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"שיחות"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"כתיבת הערות"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"הוספה"</string>
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"בלי להציע את האפליקציה"</string>
<string name="pin_prediction" msgid="4196423321649756498">"הצמדת החיזוי"</string>
+ <string name="bubble" msgid="3072951361014076670">"בועה"</string>
<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..d2f9a97 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"インストール"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"アプリを表示しない"</string>
<string name="pin_prediction" msgid="4196423321649756498">"アプリの候補を固定"</string>
+ <string name="bubble" msgid="3072951361014076670">"ふきだし"</string>
<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..e67cc41 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
+ <string name="bubble" msgid="3072951361014076670">"ბუშტი"</string>
<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..d5ccae5 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Болжамды бекіту"</string>
+ <string name="bubble" msgid="3072951361014076670">"Қалқыма терезе"</string>
<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..3c9135b 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ខ្ទាស់ការព្យាករ"</string>
+ <string name="bubble" msgid="3072951361014076670">"ពពុះ"</string>
<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..ab84833 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ಮುನ್ನೋಟ ಪಿನ್ ಮಾಡಿ"</string>
+ <string name="bubble" msgid="3072951361014076670">"ಬಬಲ್"</string>
<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..318cd00 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
<string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
+ <string name="bubble" msgid="3072951361014076670">"풍선"</string>
<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..856e2b2 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/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,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Көбүкчө"</string>
<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..3d1a6c9 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ຢ່າແນະນຳແອັບ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ປັກໝຸດການຄາດເດົາ"</string>
+ <string name="bubble" msgid="3072951361014076670">"ຟອງ"</string>
<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..4c9bd9b 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Debesėlis"</string>
<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..0a82705 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Burbulis"</string>
<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..887ca82 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
+ <string name="bubble" msgid="3072951361014076670">"Балонче"</string>
<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..dda5679 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,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
<string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
+ <string name="bubble" msgid="3072951361014076670">"ബബിൾ"</string>
<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..49d71c2 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Апп бүү санал болго"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Таамаглалыг бэхлэх"</string>
+ <string name="bubble" msgid="3072951361014076670">"Бөмбөлөг"</string>
<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..fdf864a 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ॲप सुचवू नका"</string>
<string name="pin_prediction" msgid="4196423321649756498">"पूर्वानुमान पिन करा"</string>
+ <string name="bubble" msgid="3072951361014076670">"बबल"</string>
<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..b86f657 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -63,7 +63,7 @@
<string name="no_widgets_available" msgid="4337693382501046170">"Widget dan pintasan tidak tersedia"</string>
<string name="no_search_results" msgid="3787956167293097509">"Tiada widget atau pintasan yang dijumpai"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Peribadi"</string>
- <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Tempat kerja"</string>
+ <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kerja"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Perbualan"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pengambilan nota"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Tambah"</string>
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Gelembung"</string>
<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..7e8fd14 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်အကြံမပြုပါနှင့်"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ခန့်မှန်းချက်ကို ပင်ထိုးရန်"</string>
+ <string name="bubble" msgid="3072951361014076670">"ပူဖောင်းကွက်"</string>
<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..2a6611f 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Boble"</string>
<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..fa2e59b 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगर्नुहोस्"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सिफारिस गरिएको एप पिन गर्नुहोस्"</string>
+ <string name="bubble" msgid="3072951361014076670">"बबल"</string>
<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-nl/strings.xml b/res/values-nl/strings.xml
index 3402086..9271b96 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bubbel"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelle links instellen"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"instellingen en snelkoppelingen op startscherm lezen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 74001c7..98d52de 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ପୂର୍ବାନୁମାନକୁ ପିନ୍ କରନ୍ତୁ"</string>
+ <string name="bubble" msgid="3072951361014076670">"ବବଲ"</string>
<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..782979e 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -63,7 +63,7 @@
<string name="no_widgets_available" msgid="4337693382501046170">"ਵਿਜੇਟ ਜਾਂ ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਨਹੀਂ ਹਨ"</string>
<string name="no_search_results" msgid="3787956167293097509">"ਕੋਈ ਵੀ ਵਿਜੇਟ ਜਾਂ ਸ਼ਾਰਟਕੱਟ ਨਹੀਂ ਮਿਲਿਆ"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ਨਿੱਜੀ"</string>
- <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ਕਾਰਜ-ਸਥਾਨ"</string>
+ <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ਕੰਮ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"ਗੱਲਾਂਬਾਤਾਂ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"ਨੋਟ ਬਣਾਉਣਾ"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"ਸ਼ਾਮਲ ਕਰੋ"</string>
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ਐਪ ਦਾ ਸੁਝਾਅ ਨਾ ਦਿਓ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ਪੂਰਵ-ਅਨੁਮਾਨ ਪਿੰਨ ਕਰੋ"</string>
+ <string name="bubble" msgid="3072951361014076670">"ਬਬਲ"</string>
<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..71e569c 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Dymek"</string>
<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..1c44d9b 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Balão"</string>
<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..3f44591 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Balão"</string>
<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..b37d93b 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Balon"</string>
<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..321bf37 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -47,7 +47,7 @@
<string name="add_item_request_drag_hint" msgid="8730547755622776606">"Нажмите на виджет и удерживайте его, чтобы переместить в нужное место на главном экране."</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Добавить на главный экран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\" добавлен на главный экран"</string>
- <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Подсказки"</string>
+ <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Рекомендованные"</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>
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
+ <string name="bubble" msgid="3072951361014076670">"Подсказка"</string>
<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..91c818a 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"යෙදුම යෝජනා නොකරන්න"</string>
<string name="pin_prediction" msgid="4196423321649756498">"පුරෝකථනය අමුණන්න"</string>
+ <string name="bubble" msgid="3072951361014076670">"බුබුළ"</string>
<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..eaae7c0 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -39,7 +39,7 @@
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržaním presuňte miniaplikáciu."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a pridržaním presuňte miniaplikáciu alebo použite vlastné akcie."</string>
<string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Ďalšie možnosti"</string>
- <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Zobrazovať všetky miniap."</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Zobrazovať všetky miniaplikácie"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"šírka %1$d, výška %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
@@ -58,12 +58,12 @@
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# odkaz}few{# odkazy}many{# shortcuts}other{# odkazov}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
<string name="widget_button_text" msgid="2880537293434387943">"Miniaplikácie"</string>
- <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Vyhľadajte"</string>
+ <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Vyhľadávanie"</string>
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Vymazať text z vyhľadávacieho poľa"</string>
<string name="no_widgets_available" msgid="4337693382501046170">"Miniaplikácie a odkazy nie sú k dispozícii"</string>
<string name="no_search_results" msgid="3787956167293097509">"Nenašli sa žiadne miniaplikácie ani odkazy"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Osobné"</string>
- <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Práca"</string>
+ <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Pracovné"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Konverzácie"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Zapisovanie poznámok"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Pridať"</string>
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bublina"</string>
<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..dccf2f1 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Mehurček"</string>
<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..84484e8 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Flluskë"</string>
<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..64383f2 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
+ <string name="bubble" msgid="3072951361014076670">"Облачић"</string>
<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..47aed86 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -62,7 +62,7 @@
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Rensa texten från sökrutan"</string>
<string name="no_widgets_available" msgid="4337693382501046170">"Widgetar och genvägar är inte tillgängliga"</string>
<string name="no_search_results" msgid="3787956167293097509">"Inga widgetar eller genvägar hittades"</string>
- <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Privata"</string>
+ <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Privat"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Arbete"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Konversationer"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Anteckna"</string>
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bubbla"</string>
<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..5eadd1d 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Kiputo"</string>
<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..d84485a 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"பரிந்துரைக்காதே"</string>
<string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்டதைப் பின் செய்"</string>
+ <string name="bubble" msgid="3072951361014076670">"குமிழ்"</string>
<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..8487e96 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్స్టాల్ చేయండి"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్ సూచించకు"</string>
<string name="pin_prediction" msgid="4196423321649756498">"సూచనను పిన్ చేయండి"</string>
+ <string name="bubble" msgid="3072951361014076670">"బబుల్"</string>
<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..71f4d15 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
+ <string name="bubble" msgid="3072951361014076670">"บับเบิล"</string>
<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..7cf6a44 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bubble"</string>
<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..d55181c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Balon"</string>
<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..b5c1c70 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"Установити"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не пропонувати додаток"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закріпити передбачений додаток"</string>
+ <string name="bubble" msgid="3072951361014076670">"Повідомлення"</string>
<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..6fa76dd 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ایپ تجویز نہ کریں"</string>
<string name="pin_prediction" msgid="4196423321649756498">"پیشگوئی پن کریں"</string>
+ <string name="bubble" msgid="3072951361014076670">"بلبلہ"</string>
<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..21a8145 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Pufaklar"</string>
<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-vi/strings.xml b/res/values-vi/strings.xml
index af4a773..b0bac73 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Bong bóng"</string>
<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 +130,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..112b945 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"安装"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要推荐此应用"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定预测的应用"</string>
+ <string name="bubble" msgid="3072951361014076670">"气泡框"</string>
<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..e63093e 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測"</string>
+ <string name="bubble" msgid="3072951361014076670">"氣泡"</string>
<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..25f9703 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -92,6 +92,7 @@
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要建議此應用程式"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
+ <string name="bubble" msgid="3072951361014076670">"泡泡"</string>
<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..ec1f941 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -92,6 +92,7 @@
<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>
+ <string name="bubble" msgid="3072951361014076670">"Ibhamuza"</string>
<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/attrs.xml b/res/values/attrs.xml
index 6151b5f..57c9bc7 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -25,7 +25,6 @@
<attr name="popupColorPrimary" format="color" />
<attr name="popupColorSecondary" format="color" />
<attr name="popupColorTertiary" format="color" />
- <attr name="popupColorBackground" format="color" />
<attr name="popupTextColor" format="color" />
<attr name="popupShadeFirst" format="color" />
<attr name="popupShadeSecond" format="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..f8c075f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -81,6 +81,11 @@
<dimen name="fastscroll_popup_text_size">32dp</dimen>
<dimen name="fastscroll_popup_margin">19dp</dimen>
+ <dimen name="fastscroll_list_letter_size">5dp</dimen>
+ <dimen name="fastscroll_list_letter_text_size">14sp</dimen>
+ <dimen name="fastscroll_list_letter_end_margin">-10dp</dimen>
+ <dimen name="bg_letter_list_text_size">20sp</dimen>
+
<!--
Fast scroller draws the content horizontally centered. The end of the track should be
aligned at the end of the container.
@@ -306,6 +311,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">0.5dp</dimen>
<!-- Pending widget -->
<dimen name="pending_widget_min_padding">8dp</dimen>
@@ -455,6 +461,7 @@
<!-- Overview placeholder to compile in Launcher3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
+ <dimen name="task_thumbnail_splash_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
<dimen name="task_thumbnail_icon_menu_drawable_touch_size">0dp</dimen>
<dimen name="task_menu_edge_padding">0dp</dimen>
@@ -481,8 +488,6 @@
<dimen name="split_instructions_bottom_margin_phone_landscape">24dp</dimen>
<dimen name="split_instructions_bottom_margin_phone_portrait">60dp</dimen>
<dimen name="split_instructions_start_margin_cancel">8dp</dimen>
- <dimen name="split_divider_handle_region_width">96dp</dimen>
- <dimen name="split_divider_handle_region_height">48dp</dimen>
<dimen name="focus_outline_radius">16dp</dimen>
<dimen name="focus_inner_outline_radius">14dp</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/res/values/styles.xml b/res/values/styles.xml
index ee7ed26..728c523 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -77,6 +77,10 @@
<item name="materialColorError">@color/system_error_light</item>
</style>
+ <style name="DynamicColorsBaseLauncherTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
<style name="LauncherTheme" parent="@style/DynamicColorsBaseLauncherTheme">
<item name="android:textColorSecondary">#DE000000</item>
@@ -86,7 +90,6 @@
<item name="popupColorPrimary">@color/popup_color_primary_light</item>
<item name="popupColorSecondary">@color/popup_color_secondary_light</item>
<item name="popupColorTertiary">@color/popup_color_tertiary_light</item>
- <item name="popupColorBackground">#EFEDED</item>
<item name="popupTextColor">@color/system_on_surface_light</item>
<item name="popupShadeFirst">@color/popup_shade_first_light</item>
<item name="popupShadeSecond">@color/popup_shade_second_light</item>
@@ -161,7 +164,6 @@
<item name="popupColorPrimary">@color/popup_color_primary_dark</item>
<item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
<item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
- <item name="popupColorBackground">#1F2020</item>
<item name="popupTextColor">@color/system_on_surface_dark</item>
<item name="popupNotificationDotColor">@color/popup_notification_dot_dark</item>
<item name="popupShadeFirst">@color/popup_shade_first_dark</item>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 876b643..76c0f90 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -74,7 +74,8 @@
TYPE_TASKBAR_ALL_APPS,
TYPE_ADD_TO_HOME_CONFIRMATION,
TYPE_TASKBAR_OVERLAY_PROXY,
- TYPE_TASKBAR_PINNING_POPUP
+ TYPE_TASKBAR_PINNING_POPUP,
+ TYPE_PIN_IME_POPUP
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
@@ -138,9 +139,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/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index ef56246..b51e850 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -37,8 +37,6 @@
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.debug.TestEvent;
-import com.android.launcher3.debug.TestEventEmitter;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.InstanceId;
@@ -223,9 +221,6 @@
dl.addView(frame);
frame.mIsOpen = true;
frame.post(() -> frame.snapToWidget(false));
- TestEventEmitter.INSTANCE.get(widget.getContext()).sendEvent(
- TestEvent.RESIZE_FRAME_SHOWING
- );
}
private void setCornerRadiusFromWidget() {
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 633091d..fec94fe 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -110,11 +110,6 @@
public static final int ACTIVITY_STATE_USER_ACTIVE = 1 << 4;
/**
- * State flag indicating if the user will be active shortly.
- */
- public static final int ACTIVITY_STATE_USER_WILL_BE_ACTIVE = 1 << 5;
-
- /**
* State flag indicating that a state transition is in progress
*/
public static final int ACTIVITY_STATE_TRANSITION_ACTIVE = 1 << 6;
@@ -316,7 +311,6 @@
*/
public void setResumed() {
addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE);
- removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
public boolean isUserActive() {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 2eb5034..8121e53 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -89,7 +89,7 @@
import com.android.launcher3.util.ShortcutUtil;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
import java.text.NumberFormat;
import java.util.HashMap;
@@ -101,7 +101,7 @@
* too aggressive.
*/
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
- IconLabelDotView, DraggableView, Reorderable {
+ FloatingIconViewCompanion, DraggableView, Reorderable {
public static final String TAG = "BubbleTextView";
@@ -176,7 +176,7 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mSkipUserBadge = false;
@ViewDebug.ExportedProperty(category = "launcher")
- private boolean mIsIconVisible = true;
+ protected boolean mIsIconVisible = true;
@ViewDebug.ExportedProperty(category = "launcher")
private int mTextColor;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -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());
@@ -1043,12 +1043,11 @@
/** Applies the given progress level to the this icon's progress bar. */
@Nullable
public PreloadIconDrawable applyProgressLevel() {
- if (!(getTag() instanceof ItemInfoWithIcon)
+ if (!(getTag() instanceof ItemInfoWithIcon info)
|| ((ItemInfoWithIcon) getTag()).isInactiveArchive()) {
return null;
}
- ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
int progressLevel = info.getProgressLevel();
if (progressLevel >= 100) {
setContentDescription(info.contentDescription != null
@@ -1068,6 +1067,10 @@
} else {
preloadIconDrawable = makePreloadIcon();
setIcon(preloadIconDrawable);
+ if (info.isArchived() && Flags.useNewIconForArchivedApps()) {
+ // reapply text without cloud icon as soon as unarchiving is triggered
+ applyLabel(info);
+ }
}
return preloadIconDrawable;
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 7e9e864..ee72c22 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -86,7 +86,7 @@
public class CellLayout extends ViewGroup {
private static final String TAG = "CellLayout";
- private static final boolean LOGD = false;
+ private static final boolean LOGD = true;
/** The color of the "leave-behind" shape when a folder is opened from Hotseat. */
private static final int FOLDER_LEAVE_BEHIND_COLOR = Color.argb(160, 245, 245, 245);
@@ -166,6 +166,7 @@
private final int[] mDragCellSpan = new int[2];
private boolean mDragging = false;
+ public boolean mHasOnLayoutBeenCalled = false;
private final TimeInterpolator mEaseOutInterpolator;
protected final ShortcutAndWidgetContainer mShortcutsAndWidgets;
@@ -1009,6 +1010,7 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ mHasOnLayoutBeenCalled = true; // b/349929393 - is the required call to onLayout not done?
int left = getPaddingLeft();
left += (int) Math.ceil(getUnusedHorizontalSpace() / 2f);
int right = r - l - getPaddingRight();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 5cbf6fb..cc5baea 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -25,7 +25,6 @@
import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_PORTRAIT;
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.Utilities.pxFromSp;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.icons.GraphicsUtils.getShapePath;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
@@ -316,6 +315,74 @@
// DragController
public int flingToDeleteThresholdVelocity;
+ /** Used only as an alternative to mocking when null values cannot be used. */
+ @VisibleForTesting
+ public DeviceProfile() {
+ inv = null;
+ mInfo = null;
+ mMetrics = null;
+ mIconSizeSteps = null;
+ isTablet = false;
+ isPhone = false;
+ transposeLayoutWithOrientation = false;
+ isMultiDisplay = false;
+ isTwoPanels = false;
+ isPredictiveBackSwipe = false;
+ isQsbInline = false;
+ isLandscape = false;
+ isMultiWindowMode = false;
+ isGestureMode = false;
+ isLeftRightSplit = false;
+ windowX = 0;
+ windowY = 0;
+ widthPx = 0;
+ heightPx = 0;
+ availableWidthPx = 0;
+ availableHeightPx = 0;
+ rotationHint = 0;
+ aspectRatio = 1;
+ mIsScalableGrid = false;
+ mTypeIndex = 0;
+ mIsResponsiveGrid = false;
+ desiredWorkspaceHorizontalMarginOriginalPx = 0;
+ edgeMarginPx = 0;
+ workspaceContentScale = 0;
+ workspaceSpringLoadedMinNextPageVisiblePx = 0;
+ extraSpace = 0;
+ workspacePageIndicatorHeight = 0;
+ mWorkspacePageIndicatorOverlapWorkspace = 0;
+ numFolderRows = 0;
+ numFolderColumns = 0;
+ folderLabelTextScale = 0;
+ areNavButtonsInline = false;
+ mHotseatBarEdgePaddingPx = 0;
+ mHotseatBarWorkspaceSpacePx = 0;
+ hotseatQsbWidth = 0;
+ hotseatQsbHeight = 0;
+ hotseatQsbVisualHeight = 0;
+ hotseatQsbShadowHeight = 0;
+ hotseatBorderSpace = 0;
+ mMinHotseatIconSpacePx = 0;
+ mMinHotseatQsbWidthPx = 0;
+ mMaxHotseatIconSpacePx = 0;
+ inlineNavButtonsEndSpacingPx = 0;
+ mBubbleBarSpaceThresholdPx = 0;
+ numShownAllAppsColumns = 0;
+ overviewActionsHeight = 0;
+ overviewActionsTopMarginPx = 0;
+ overviewActionsButtonSpacing = 0;
+ mViewScaleProvider = null;
+ mDotRendererWorkSpace = null;
+ mDotRendererAllApps = null;
+ taskbarHeight = 0;
+ stashedTaskbarHeight = 0;
+ taskbarBottomMargin = 0;
+ taskbarIconSize = 0;
+ mTransientTaskbarClaimedSpace = 0;
+ startAlignTaskbar = false;
+ isTransientTaskbar = false;
+ }
+
/** TODO: Once we fully migrate to staged split, remove "isMultiWindowMode" */
DeviceProfile(Context context, InvariantDeviceProfile inv, Info info, WindowBounds windowBounds,
SparseArray<DotRenderer> dotRendererCache, boolean isMultiWindowMode,
@@ -435,7 +502,7 @@
bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration);
if (isTablet) {
bottomSheetWorkspaceScale = workspaceContentScale;
- if (isMultiDisplay && !ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH.get()) {
+ if (isMultiDisplay) {
// TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth
// when screen recorder bug is fixed.
if (enableScalingRevealHomeAnimation()) {
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 960d77a..6622e11 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -20,16 +20,15 @@
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;
import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -56,9 +55,11 @@
super(context, attrs, defStyleAttr);
}
- public void bindFastScrollbar(RecyclerViewFastScroller scrollbar) {
+ public void bindFastScrollbar(RecyclerViewFastScroller scrollbar,
+ RecyclerViewFastScroller.FastScrollerLocation location) {
mScrollbar = scrollbar;
mScrollbar.setRecyclerView(this);
+ mScrollbar.setFastScrollerLocation(location);
onUpdateScrollbar(0);
}
@@ -165,6 +166,13 @@
public abstract void onUpdateScrollbar(int dy);
/**
+ * Return the fast scroll letter list view in the A-Z list.
+ */
+ public ConstraintLayout getLetterList() {
+ return null;
+ }
+
+ /**
* <p>Override in each subclass of this base class.
*/
public void onFastScrollCompleted() {}
@@ -189,10 +197,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..365e3d4 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -135,14 +135,12 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
-import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
-import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
@@ -214,7 +212,6 @@
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.popup.PopupDataProvider;
@@ -244,6 +241,7 @@
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener;
import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.util.StableViewInfo;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
@@ -438,6 +436,10 @@
mIsColdStartupAfterReboot = sIsNewProcess
&& !LockedUserState.get(this).isUserUnlockedAtLauncherStartup();
if (mIsColdStartupAfterReboot) {
+ /*
+ * This trace is used to calculate the time from create to the point that icons are
+ * visible.
+ */
Trace.beginAsyncSection(
COLD_STARTUP_TRACE_METHOD_NAME, COLD_STARTUP_TRACE_COOKIE);
}
@@ -1410,15 +1412,6 @@
this, R.attr.isWorkspaceDarkText) ? Color.BLACK : Color.WHITE);
}
- @Override
- public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
- if (WorkspacePageIndicator.class.getName().equals(name)) {
- return LayoutInflater.from(context).inflate(R.layout.page_indicator_dots,
- (ViewGroup) parent, false);
- }
- return super.onCreateView(parent, name, context, attrs);
- }
-
/**
* Add a shortcut to the workspace or to a Folder.
*
@@ -2396,10 +2389,6 @@
.logEnd(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
.log()
.reset();
- if (mIsColdStartupAfterReboot) {
- Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
- COLD_STARTUP_TRACE_COOKIE);
- }
});
}
@@ -2408,6 +2397,10 @@
RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, onCompleteSignal,
workspaceItemCount, isBindSync);
+ if (mIsColdStartupAfterReboot) {
+ Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
+ COLD_STARTUP_TRACE_COOKIE);
+ }
}
/**
@@ -2432,17 +2425,16 @@
* Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
* animation.
*
- * @param preferredItemId The id of the preferred item to match to if it exists,
- * or ItemInfo#NO_MATCHING_ID if you want to not match by item id
+ * @param svi The StableViewInfo of the preferred item to match to if it exists or null
* @param packageName The package name of the app to match.
* @param user The user of the app to match.
* @param supportsAllAppsState If true and we are in All Apps state, looks for view in All Apps.
* Else we only looks on the workspace.
*/
- public @Nullable View getFirstMatchForAppClose(int preferredItemId, String packageName,
+ public @Nullable View getFirstMatchForAppClose(
+ @Nullable StableViewInfo svi, String packageName,
UserHandle user, boolean supportsAllAppsState) {
- final Predicate<ItemInfo> preferredItem = info ->
- info != null && info.id == preferredItemId;
+ final Predicate<ItemInfo> preferredItem = svi == null ? i -> false : svi::matches;
final Predicate<ItemInfo> packageAndUserAndApp = info ->
info != null
&& info.itemType == ITEM_TYPE_APPLICATION
@@ -2533,6 +2525,9 @@
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
View item = container.getChildAt(itemIdx);
+ if (item.getVisibility() != View.VISIBLE) {
+ continue;
+ }
if (item instanceof ViewGroup viewGroup) {
View view = mapOverViewGroup(viewGroup, op);
if (view != null) {
@@ -2701,6 +2696,20 @@
writer.println(prefix + "\tmAppWidgetHolder.isListening: "
+ mAppWidgetHolder.isListening());
+ // b/349929393
+ // The only way to reproduce this bug is to ensure that onLayout never gets called. This
+ // theoretically is impossible, so these logs are being added to test if that actually is
+ // what is happening.
+ writer.println(prefix + "\tmWorkspace.mHasOnLayoutBeenCalled="
+ + mWorkspace.mHasOnLayoutBeenCalled);
+ for (int i = 0; i < mWorkspace.getPageCount(); i++) {
+ CellLayout cellLayout = (CellLayout) mWorkspace.getPageAt(i);
+ writer.println(prefix + "\tcellLayout." + i + ".mHasOnLayoutBeenCalled="
+ + cellLayout.mHasOnLayoutBeenCalled);
+ writer.println(prefix + "\tshortcutAndWidgetContainer." + i + ".mHasOnLayoutBeenCalled="
+ + cellLayout.getShortcutsAndWidgets().mHasOnLayoutBeenCalled);
+ }
+
// Extra logging for general debugging
mDragLayer.dump(prefix, writer);
mStateManager.dump(prefix, writer);
@@ -2708,6 +2717,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);
@@ -3026,6 +3039,7 @@
return mPopupDataProvider.getDotInfoForItem(info);
}
+ @NonNull
public LauncherOverlayManager getOverlayManager() {
return mOverlayManager;
}
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 40873be..490186a 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -17,14 +17,23 @@
import android.app.Application;
+import com.android.launcher3.dagger.DaggerLauncherAppComponent;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
+
/**
* Main application class for Launcher
*/
public class LauncherApplication extends Application {
+ private LauncherBaseAppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
MainProcessInitializer.initialize(this);
+ mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build();
+ }
+
+ public LauncherBaseAppComponent getAppComponent() {
+ return mAppComponent;
}
}
diff --git a/src/com/android/launcher3/MotionEventsUtils.java b/src/com/android/launcher3/MotionEventsUtils.java
index 3228ec6..fb244b0 100644
--- a/src/com/android/launcher3/MotionEventsUtils.java
+++ b/src/com/android/launcher3/MotionEventsUtils.java
@@ -18,8 +18,6 @@
import static android.view.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
-
import android.annotation.TargetApi;
import android.os.Build;
import android.view.MotionEvent;
@@ -35,14 +33,12 @@
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static boolean isTrackpadScroll(MotionEvent event) {
- return ENABLE_TRACKPAD_GESTURE.get()
- && event.getClassification() == CLASSIFICATION_TWO_FINGER_SWIPE;
+ return event.getClassification() == CLASSIFICATION_TWO_FINGER_SWIPE;
}
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static boolean isTrackpadMultiFingerSwipe(MotionEvent event) {
- return ENABLE_TRACKPAD_GESTURE.get()
- && event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE;
+ return event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE;
}
public static boolean isTrackpadThreeFingerSwipe(MotionEvent event) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 365fbd3..0ec3b79 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1463,6 +1463,15 @@
mEdgeGlowLeft.onFlingVelocity(velocity);
mEdgeGlowRight.onFlingVelocity(velocity);
}
+
+ // Detect if user tries to swipe to -1 page but gets disallowed by checking if there was
+ // left-over values in mEdgeGlowLeft (or mEdgeGlowRight in RLT).
+ final int layoutDir = getLayoutDirection();
+ if ((mEdgeGlowLeft.getDistance() > 0 && layoutDir == LAYOUT_DIRECTION_LTR)
+ || (mEdgeGlowRight.getDistance() > 0 && layoutDir == LAYOUT_DIRECTION_RTL)) {
+ onDisallowSwipeToMinusOnePage();
+ }
+
mEdgeGlowLeft.onRelease(ev);
mEdgeGlowRight.onRelease(ev);
// End any intermediate reordering states
@@ -1487,6 +1496,8 @@
return true;
}
+ protected void onDisallowSwipeToMinusOnePage() {}
+
protected void onNotSnappingToPageInFreeScroll() { }
/**
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index d2c3c78..a8733f2 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -64,6 +64,7 @@
private final ActivityContext mActivity;
private boolean mInvertIfRtl = false;
+ public boolean mHasOnLayoutBeenCalled = false;
@Nullable
private TranslationProvider mTranslationProvider = null;
@@ -201,6 +202,7 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Trace.beginSection("ShortcutAndWidgetConteiner#onLayout");
+ mHasOnLayoutBeenCalled = true; // b/349929393 - is the required call to onLayout not done?
int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 2995e8a..0e9c861 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -235,6 +235,7 @@
boolean mChildrenLayersEnabled = true;
private boolean mStripScreensOnPageStopMoving = false;
+ public boolean mHasOnLayoutBeenCalled = false;
private boolean mWorkspaceFadeInAdjacentScreens;
@@ -1122,6 +1123,11 @@
return super.onTouchEvent(ev);
}
+ @Override
+ protected void onDisallowSwipeToMinusOnePage() {
+ mLauncher.getOverlayManager().onDisallowSwipeToMinusOnePage();
+ }
+
/**
* Called directly from a CellLayout (not by the framework), after we've been added as a
* listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
@@ -1445,6 +1451,7 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ mHasOnLayoutBeenCalled = true; // b/349929393 - is the required call to onLayout not done?
if (mUnlockWallpaperFromDefaultPageOnLayout) {
mWallpaperOffset.setLockToDefaultPage(false);
mUnlockWallpaperFromDefaultPageOnLayout = false;
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index ad660d2..6b5e3be 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -18,16 +18,16 @@
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;
-import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.ALL_APPS_SCROLLER;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -64,6 +64,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.VisibleForTesting;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.RecyclerView;
@@ -167,6 +168,7 @@
protected FloatingHeaderView mHeader;
protected View mBottomSheetBackground;
protected RecyclerViewFastScroller mFastScroller;
+ private ConstraintLayout mFastScrollLetterLayout;
/**
* View that defines the search box. Result is rendered inside {@link #mSearchRecyclerView}.
@@ -281,6 +283,13 @@
mSearchRecyclerView = findViewById(R.id.search_results_list_view);
mFastScroller = findViewById(R.id.fast_scroller);
mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
+ mFastScrollLetterLayout = findViewById(R.id.scroll_letter_layout);
+ if (Flags.letterFastScroller()) {
+ // Set clip children to false otherwise the scroller letters will be clipped.
+ setClipChildren(false);
+ } else {
+ setClipChildren(true);
+ }
mSearchContainer = inflateSearchBar();
if (!isSearchBarFloating()) {
@@ -562,7 +571,8 @@
mActivityContext.hideKeyboard();
}
if (mAH.get(currentActivePage).mRecyclerView != null) {
- mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar(mFastScroller);
+ mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar(mFastScroller,
+ ALL_APPS_SCROLLER);
}
// Header keeps track of active recycler view to properly render header protection.
mHeader.setActiveRV(currentActivePage);
@@ -667,18 +677,13 @@
@NonNull AllAppsRecyclerView mainRecyclerView,
@Nullable AllAppsRecyclerView workRecyclerView,
@NonNull AllAppsRecyclerViewPool recycledViewPool) {
- if (!ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
- return;
- }
final boolean hasWorkProfile = workRecyclerView != null;
recycledViewPool.setHasWorkProfile(hasWorkProfile);
mainRecyclerView.setRecycledViewPool(recycledViewPool);
if (workRecyclerView != null) {
workRecyclerView.setRecycledViewPool(recycledViewPool);
}
- if (ALL_APPS_GONE_VISIBILITY.get()) {
- mainRecyclerView.updatePoolSize(hasWorkProfile);
- }
+ mainRecyclerView.updatePoolSize(hasWorkProfile);
}
private void replaceAppsRVContainer(boolean showTabs) {
@@ -1313,6 +1318,10 @@
return mAH.get(MAIN).mAppsList;
}
+ public AlphabeticalAppsList<T> getWorkAppList() {
+ return mAH.get(WORK).mAppsList;
+ }
+
public FloatingHeaderView getFloatingHeaderView() {
return mHeader;
}
@@ -1495,6 +1504,10 @@
}
}
+ ConstraintLayout getFastScrollerLetterList() {
+ return mFastScrollLetterLayout;
+ }
+
/**
* redraws header protection
*/
@@ -1562,7 +1575,7 @@
void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
mAppsList.updateItemFilter(matcher);
mRecyclerView = (AllAppsRecyclerView) rv;
- mRecyclerView.bindFastScrollbar(mFastScroller);
+ mRecyclerView.bindFastScrollbar(mFastScroller, ALL_APPS_SCROLLER);
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
mRecyclerView.setApps(mAppsList);
mRecyclerView.setLayoutManager(mLayoutManager);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 2a47222..4e1e950 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -15,8 +15,9 @@
*/
package com.android.launcher3.allapps;
-import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
+import static androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT;
+import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
+
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import static com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_PERSONAL_SCROLLED_DOWN;
@@ -36,22 +37,29 @@
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
+import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.util.Consumer;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.FastScrollRecyclerView;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.views.ActivityContext;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -66,6 +74,7 @@
protected final int mNumAppsPerRow;
private final AllAppsFastScrollHelper mFastScrollHelper;
private int mCumulativeVerticalScroll;
+ private ConstraintLayout mLetterList;
protected AlphabeticalAppsList<?> mApps;
@@ -113,13 +122,11 @@
// all apps.
int maxPoolSizeForAppIcons = grid.getMaxAllAppsRowCount()
* grid.numShownAllAppsColumns;
- if (ALL_APPS_GONE_VISIBILITY.get() && ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
- // If we set all apps' hidden visibility to GONE and enable pre-inflation, we want to
- // preinflate one page of all apps icons plus [PREINFLATE_ICONS_ROW_COUNT] rows +
- // [EXTRA_ICONS_COUNT]. Thus we need to bump the max pool size of app icons accordingly.
- maxPoolSizeForAppIcons +=
- PREINFLATE_ICONS_ROW_COUNT * grid.numShownAllAppsColumns + EXTRA_ICONS_COUNT;
- }
+ // If we set all apps' hidden visibility to GONE and enable pre-inflation, we want to
+ // preinflate one page of all apps icons plus [PREINFLATE_ICONS_ROW_COUNT] rows +
+ // [EXTRA_ICONS_COUNT]. Thus we need to bump the max pool size of app icons accordingly.
+ maxPoolSizeForAppIcons +=
+ PREINFLATE_ICONS_ROW_COUNT * grid.numShownAllAppsColumns + EXTRA_ICONS_COUNT;
if (hasWorkProfile) {
maxPoolSizeForAppIcons *= 2;
}
@@ -238,6 +245,9 @@
return;
}
+ if (Flags.letterFastScroller() && !mScrollbar.isDraggingThumb()) {
+ setLettersToScrollLayout(mApps.getFastScrollerSections());
+ }
// Only show the scrollbar if there is height to be scrolled
int availableScrollBarHeight = getAvailableScrollBarHeight();
int availableScrollHeight = getAvailableScrollHeight();
@@ -319,6 +329,80 @@
return false;
}
+ public void setLettersToScrollLayout(
+ List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections) {
+ if (mLetterList != null) {
+ mLetterList.removeAllViews();
+ }
+ Context context = getContext();
+ ActivityAllAppsContainerView<?> allAppsContainerView =
+ ActivityContext.lookupContext(context).getAppsView();
+ mLetterList = allAppsContainerView.getFastScrollerLetterList();
+ mLetterList.setPadding(0, getScrollBarTop(), 0, getScrollBarMarginBottom());
+ List<LetterListTextView> textViews = new ArrayList<>();
+ for (int i = 0; i < fastScrollSections.size(); i++) {
+ AlphabeticalAppsList.FastScrollSectionInfo sectionInfo = fastScrollSections.get(i);
+ LetterListTextView textView =
+ (LetterListTextView) LayoutInflater.from(context).inflate(
+ R.layout.fast_scroller_letter_list_text_view, mLetterList, false);
+ int viewId = View.generateViewId();
+ textView.setId(viewId);
+ sectionInfo.setId(viewId);
+ textView.setText(sectionInfo.sectionName);
+ if (i == fastScrollSections.size() - 1) {
+ // The last section info is just a duplicate so that user can scroll to the bottom.
+ textView.setVisibility(INVISIBLE);
+ }
+ ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
+ MATCH_CONSTRAINT, WRAP_CONTENT);
+ lp.dimensionRatio = "v,1:1";
+ textView.setLayoutParams(lp);
+ textViews.add(textView);
+ mLetterList.addView(textView);
+ }
+ // Need to add an extra textview to be aligned.
+ LetterListTextView lastLetterListTextView = new LetterListTextView(context);
+ int currentId = View.generateViewId();
+ lastLetterListTextView.setId(currentId);
+ lastLetterListTextView.setVisibility(INVISIBLE);
+ textViews.add(lastLetterListTextView);
+ mLetterList.addView(lastLetterListTextView);
+ constraintTextViewsVertically(mLetterList, textViews);
+ mLetterList.setVisibility(VISIBLE);
+ }
+
+ private void constraintTextViewsVertically(ConstraintLayout constraintLayout,
+ List<LetterListTextView> textViews) {
+ ConstraintSet chain = new ConstraintSet();
+ chain.clone(constraintLayout);
+ for (int i = 0; i < textViews.size(); i++) {
+ LetterListTextView currentView = textViews.get(i);
+ if (i == 0) {
+ chain.connect(currentView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID,
+ ConstraintSet.TOP);
+ } else {
+ chain.connect(currentView.getId(), ConstraintSet.TOP, textViews.get(i-1).getId(),
+ ConstraintSet.BOTTOM);
+ }
+ chain.connect(currentView.getId(), ConstraintSet.START, constraintLayout.getId(),
+ ConstraintSet.START);
+ chain.connect(currentView.getId(), ConstraintSet.END, constraintLayout.getId(),
+ ConstraintSet.END);
+ }
+ int[] viewIds = textViews.stream().mapToInt(TextView::getId).toArray();
+ float[] weights = new float[textViews.size()];
+ Arrays.fill(weights,1); // fill with 1 for equal weights
+ chain.createVerticalChain(constraintLayout.getId(), ConstraintSet.TOP,
+ constraintLayout.getId(), ConstraintSet.BOTTOM, viewIds, weights,
+ ConstraintSet.CHAIN_SPREAD);
+ chain.applyTo(constraintLayout);
+ }
+
+ @Override
+ public ConstraintLayout getLetterList() {
+ return mLetterList;
+ }
+
private void logCumulativeVerticalScroll() {
ActivityContext context = ActivityContext.lookupContext(getContext());
StatsLogManager mgr = context.getStatsLogManager();
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index a4f130a..29b9e77 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.allapps;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
@@ -109,7 +108,7 @@
mPackageUserKeytoUidMap = map;
// Preinflate all apps RV when apps has changed, which can happen after unlocking screen,
// rotating screen, or downloading/upgrading apps.
- if (shouldPreinflate && ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
+ if (shouldPreinflate) {
mAllAppsRecyclerViewPool.preInflateAllAppsViewHolders(mContext);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 1b0ad04..c6852e0 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -37,7 +37,6 @@
import android.animation.Animator;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.util.FloatProperty;
import android.view.HapticFeedbackConstants;
import android.view.View;
@@ -52,11 +51,9 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AllAppsSwipeController;
@@ -359,22 +356,6 @@
});
}
- if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && config.isUserControlled()
- && Utilities.ATLEAST_S) {
- if (toState == ALL_APPS) {
- builder.addOnFrameListener(
- new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
- SWIPE_DRAG_COMMIT_THRESHOLD, 1));
- } else {
- builder.addOnFrameListener(
- new VibrationAnimatorUpdateListener(this, mVibratorWrapper,
- 0, SWIPE_DRAG_COMMIT_THRESHOLD));
- }
- builder.addEndListener((unused) -> {
- mVibratorWrapper.cancelVibrate();
- });
- }
-
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -391,8 +372,7 @@
setAlphas(toState, config, builder);
// This controls both haptics for tapping on QSB and going to all apps.
- if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL) &&
- !FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get()) {
+ if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL)) {
mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
}
@@ -432,8 +412,7 @@
mAppsView = appsView;
mAppsView.setScrimView(scrimView);
- mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT,
- FeatureFlags.ALL_APPS_GONE_VISIBILITY.get() ? View.GONE : View.INVISIBLE);
+ mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT, View.GONE);
mAppsViewAlpha.setUpdateVisibility(true);
mAppsViewTranslationY = new MultiPropertyFactory<>(
mAppsView, VIEW_TRANSLATE_Y, APPS_VIEW_INDEX_COUNT, Float::sum);
@@ -445,45 +424,4 @@
public void setShiftRange(float shiftRange) {
mShiftRange = shiftRange;
}
-
- /**
- * This VibrationAnimatorUpdateListener class takes in four parameters, a controller, start
- * threshold, end threshold, and a Vibrator wrapper. We use the progress given by the controller
- * as it gives an accurate progress that dictates where the vibrator should vibrate.
- * Note: once the user begins a gesture and does the commit haptic, there should not be anymore
- * haptics played for that gesture.
- */
- private static class VibrationAnimatorUpdateListener implements
- ValueAnimator.AnimatorUpdateListener {
- private final VibratorWrapper mVibratorWrapper;
- private final AllAppsTransitionController mController;
- private final float mStartThreshold;
- private final float mEndThreshold;
- private boolean mHasCommitted;
-
- VibrationAnimatorUpdateListener(AllAppsTransitionController controller,
- VibratorWrapper vibratorWrapper, float startThreshold,
- float endThreshold) {
- mController = controller;
- mVibratorWrapper = vibratorWrapper;
- mStartThreshold = startThreshold;
- mEndThreshold = endThreshold;
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- if (mHasCommitted) {
- return;
- }
- float currentProgress =
- AllAppsTransitionController.ALL_APPS_PROGRESS.get(mController);
- if (currentProgress > mStartThreshold && currentProgress < mEndThreshold) {
- mVibratorWrapper.vibrateForDragTexture();
- } else if (!(currentProgress == 0 || currentProgress == 1)) {
- // This check guards against committing at the location of the start of the gesture
- mVibratorWrapper.vibrateForDragCommit();
- mHasCommitted = true;
- }
- }
- }
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index a3cabc2..8e44d65 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;
@@ -72,11 +74,17 @@
public final CharSequence sectionName;
// The item position
public final int position;
+ // The view id associated with this section
+ public int id = -1;
public FastScrollSectionInfo(CharSequence sectionName, int position) {
this.sectionName = sectionName;
this.position = position;
}
+
+ public void setId(int id) {
+ this.id = id;
+ }
}
@@ -270,6 +278,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 +299,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 +313,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 +357,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,6 +419,7 @@
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.
@@ -421,6 +434,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));
@@ -471,6 +486,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/allapps/LetterListTextView.java b/src/com/android/launcher3/allapps/LetterListTextView.java
new file mode 100644
index 0000000..9326d79
--- /dev/null
+++ b/src/com/android/launcher3/allapps/LetterListTextView.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import androidx.core.graphics.ColorUtils;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Themes;
+
+/**
+ * A TextView that is used to display the letter list in the fast scroller.
+ */
+public class LetterListTextView extends TextView {
+ private static final float ABSOLUTE_TRANSLATION_X = 30f;
+ private static final float ABSOLUTE_SCALE = 1.4f;
+ private final Drawable mLetterBackground;
+ private final int mLetterListTextWidthAndHeight;
+ private final int mTextColor;
+ private final int mBackgroundColor;
+ private final int mSelectedColor;
+
+ public LetterListTextView(Context context) {
+ this(context, null, 0);
+ }
+
+ public LetterListTextView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LetterListTextView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mLetterBackground = context.getDrawable(R.drawable.bg_letter_list_text);
+ mLetterListTextWidthAndHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.fastscroll_list_letter_size);
+ mTextColor = Themes.getAttrColor(context, R.attr.materialColorOnSurface);
+ mBackgroundColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceContainer);
+ mSelectedColor = Themes.getAttrColor(context, R.attr.materialColorOnSecondary);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ setBackground(mLetterBackground);
+ setTextColor(mTextColor);
+ setClickable(false);
+ setWidth(mLetterListTextWidthAndHeight);
+ setTextSize(mLetterListTextWidthAndHeight);
+ setVisibility(VISIBLE);
+ }
+
+ /**
+ * Animates the letter list text view based on the current finger position.
+ *
+ * @param currentFingerY The Y position of where the finger is placed on the fastScroller in
+ * pixels.
+ */
+ public void animateBasedOnYPosition(int currentFingerY) {
+ if (getBackground() == null) {
+ return;
+ }
+ float cutOffMin = currentFingerY - (getHeight() * 2);
+ float cutOffMax = currentFingerY + (getHeight() * 2);
+ float cutOffDistance = cutOffMax - cutOffMin;
+ // Update the background blend color
+ boolean isWithinAnimationBounds = getY() < cutOffMax && getY() > cutOffMin;
+ if (isWithinAnimationBounds) {
+ getBackground().setColorFilter(new PorterDuffColorFilter(
+ getBlendColorBasedOnYPosition(currentFingerY, cutOffDistance),
+ PorterDuff.Mode.MULTIPLY));
+ } else {
+ getBackground().setColorFilter(new PorterDuffColorFilter(
+ mBackgroundColor, PorterDuff.Mode.MULTIPLY));
+ }
+ translateBasedOnYPosition(currentFingerY, cutOffDistance, isWithinAnimationBounds);
+ scaleBasedOnYPosition(currentFingerY, cutOffDistance, isWithinAnimationBounds);
+ }
+
+ private int getBlendColorBasedOnYPosition(int y, float cutOffDistance) {
+ float raisedCosineBlend = (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI);
+ float blendRatio = Utilities.boundToRange(raisedCosineBlend, 0f, 1f);
+ return ColorUtils.blendARGB(mBackgroundColor, mSelectedColor, blendRatio);
+ }
+
+ private void scaleBasedOnYPosition(int y, float cutOffDistance,
+ boolean isWithinAnimationBounds) {
+ float raisedCosineScale = (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI)
+ * ABSOLUTE_SCALE;
+ if (isWithinAnimationBounds) {
+ raisedCosineScale = Utilities.boundToRange(raisedCosineScale, 1f, ABSOLUTE_SCALE);
+ setScaleX(raisedCosineScale);
+ setScaleY(raisedCosineScale);
+ } else {
+ setScaleX(1);
+ setScaleY(1);
+ }
+ }
+
+ private void translateBasedOnYPosition(int y, float cutOffDistance,
+ boolean isWithinAnimationBounds) {
+ float raisedCosineTranslation =
+ (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI)
+ * ABSOLUTE_TRANSLATION_X;
+ if (isWithinAnimationBounds) {
+ raisedCosineTranslation = -1 * Utilities.boundToRange(raisedCosineTranslation,
+ 0, ABSOLUTE_TRANSLATION_X);
+ setTranslationX(raisedCosineTranslation);
+ } else {
+ setTranslationX(0);
+ }
+ }
+}
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/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index d0596fa..eb65320 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -62,17 +62,10 @@
* and set a default value for the flag. This will be the default value on Debug builds.
* <p>
*/
- // TODO(Block 2): Clean up flags
- public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag(270395073,
- "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", DISABLED,
- "Allow bottom sheet depth to be smaller than 1 for multi-display devices.");
-
// TODO(Block 3): Clean up flags
public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
"ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
"Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
- public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
- "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");
public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424,
"ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED,
@@ -85,26 +78,10 @@
+ "data preparation for loading the home screen");
// TODO(Block 4): Cleanup flags
- public static final BooleanFlag ENABLE_ALL_APPS_FROM_OVERVIEW =
- getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
- "Allow entering All Apps from Overview (e.g. long swipe up from app)");
-
public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
"Enable option to show keyboard when going to all-apps");
- // TODO(Block 5): Clean up flags
- public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851,
- "ENABLE_TWOLINE_DEVICESEARCH", DISABLED,
- "Enable two line label for icons with labels on device search.");
-
- public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143,
- "ENABLE_ICON_IN_TEXT_HEADER", DISABLED, "Show icon in textheader");
-
- public static final BooleanFlag ENABLE_PREMIUM_HAPTICS_ALL_APPS = getDebugFlag(270396358,
- "ENABLE_PREMIUM_HAPTICS_ALL_APPS", DISABLED,
- "Enables haptics opening/closing All apps");
-
// TODO(Block 6): Clean up flags
public static final BooleanFlag ENABLE_ALL_APPS_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
"ENABLE_ALL_APPS_SEARCH_IN_TASKBAR", ENABLED,
@@ -125,10 +102,6 @@
public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
"FOLDABLE_SINGLE_PAGE", DISABLED, "Use a single page for the workspace");
- public static final BooleanFlag ENABLE_PARAMETRIZE_REORDER = getDebugFlag(289420844,
- "ENABLE_PARAMETRIZE_REORDER", DISABLED,
- "Enables generating the reorder using a set of parameters");
-
// TODO(Block 12): Clean up flags
public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
"ENABLE_MULTI_INSTANCE", DISABLED,
@@ -175,10 +148,6 @@
public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012,
"PROMISE_APPS_IN_ALL_APPS", DISABLED, "Add promise icon in all-apps");
- public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(270390904,
- "KEYGUARD_ANIMATION", DISABLED,
- "Enable animation for keyguard going away on wallpaper");
-
public static final BooleanFlag ENABLE_DEVICE_SEARCH = getReleaseFlag(270390907,
"ENABLE_DEVICE_SEARCH", ENABLED, "Allows on device search in all apps");
@@ -235,17 +204,6 @@
"ENABLE_SEARCH_UNINSTALLED_APPS", ENABLED, "Search uninstalled app results.");
// TODO(Block 20): Clean up flags
- public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(270393276,
- "ENABLE_SCRIM_FOR_APP_LAUNCH", DISABLED, "Enables scrim during app launch animation.");
-
- public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(270393426,
- "ENABLE_BACK_SWIPE_HOME_ANIMATION", ENABLED,
- "Enables home animation to icon when user swipes back.");
-
- public static final BooleanFlag ENABLE_DYNAMIC_TASKBAR_THRESHOLDS = getDebugFlag(294252473,
- "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", ENABLED,
- "Enables taskbar thresholds that scale based on screen size.");
-
// Aconfig migration complete for ENABLE_HOME_TRANSITION_LISTENER.
public static final BooleanFlag ENABLE_HOME_TRANSITION_LISTENER = getDebugFlag(306053414,
"ENABLE_HOME_TRANSITION_LISTENER", DISABLED,
@@ -264,18 +222,7 @@
"ENABLE_WIDGET_TRANSITION_FOR_RESIZING", DISABLED,
"Enable widget transition animation when resizing the widgets");
- public static final BooleanFlag PREEMPTIVE_UNFOLD_ANIMATION_START = getDebugFlag(270397209,
- "PREEMPTIVE_UNFOLD_ANIMATION_START", ENABLED,
- "Enables starting the unfold animation preemptively when unfolding, without"
- + "waiting for SystemUI and then merging the SystemUI progress whenever we "
- + "start receiving the events");
-
// TODO(Block 25): Clean up flags
- public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
- "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
- "Enable the redesigned gesture navigation tutorial");
-
- // TODO(Block 26): Clean up flags
public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(270394384,
"ENABLE_WIDGET_HOST_IN_BACKGROUND", ENABLED,
"Enable background widget updates listening for widget holder");
@@ -300,10 +247,6 @@
"SEPARATE_RECENTS_ACTIVITY", DISABLED,
"Uses a separate recents activity instead of using the integrated recents+Launcher UI");
- public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = getReleaseFlag(270393258,
- "ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED,
- "Enforce rounded corners on all App Widgets");
-
public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973,
"USE_LOCAL_ICON_OVERRIDES", ENABLED,
"Use inbuilt monochrome icons if app doesn't provide one");
@@ -317,21 +260,11 @@
com.android.wm.shell.Flags.enableSplitContextual();
}
- public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401,
- "ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture.");
-
// TODO(Block 29): Clean up flags
public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897,
"ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", DISABLED,
"Enables displaying the all apps button in the hotseat.");
- public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844,
- "ENABLE_KEYBOARD_QUICK_SWITCH", ENABLED, "Enables keyboard quick switching");
-
- public static final BooleanFlag ENABLE_KEYBOARD_TASKBAR_TOGGLE = getDebugFlag(281726846,
- "ENABLE_KEYBOARD_TASKBAR_TOGGLE", ENABLED,
- "Enables keyboard taskbar stash toggling");
-
// TODO(Block 30): Clean up flags
public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010,
"USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", DISABLED,
@@ -349,14 +282,6 @@
return ENABLE_RESPONSIVE_WORKSPACE.get() || Flags.enableResponsiveWorkspace();
}
- // TODO(Block 33): Clean up flags
- public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355,
- "ENABLE_ALL_APPS_RV_PREINFLATION", ENABLED,
- "Enables preinflating all apps icons to avoid scrolling jank.");
- public static final BooleanFlag ALL_APPS_GONE_VISIBILITY = getDebugFlag(291651514,
- "ALL_APPS_GONE_VISIBILITY", ENABLED,
- "Set all apps container view's hidden visibility to GONE instead of INVISIBLE.");
-
public static BooleanFlag getDebugFlag(
int bugId, String key, BooleanFlag flagState, String description) {
return flagState;
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/dagger/ActivityContextScope.java b/src/com/android/launcher3/dagger/ActivityContextScope.java
new file mode 100644
index 0000000..887f15c
--- /dev/null
+++ b/src/com/android/launcher3/dagger/ActivityContextScope.java
@@ -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.dagger;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singletons associated with Launcher activity context.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Scope
+public @interface ActivityContextScope {
+}
diff --git a/src/com/android/launcher3/dagger/ApplicationContext.java b/src/com/android/launcher3/dagger/ApplicationContext.java
new file mode 100644
index 0000000..9a5b08b
--- /dev/null
+++ b/src/com/android/launcher3/dagger/ApplicationContext.java
@@ -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.dagger;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/**
+ * Qualifier for Launcher application context.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+public @interface ApplicationContext {
+}
diff --git a/src/com/android/launcher3/dagger/LauncherAppSingleton.java b/src/com/android/launcher3/dagger/LauncherAppSingleton.java
new file mode 100644
index 0000000..92c00b6
--- /dev/null
+++ b/src/com/android/launcher3/dagger/LauncherAppSingleton.java
@@ -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.dagger;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singleton items within the LauncherAppComponent.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Scope
+public @interface LauncherAppSingleton {
+}
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
new file mode 100644
index 0000000..1a59d82
--- /dev/null
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dagger;
+
+import android.content.Context;
+
+import dagger.BindsInstance;
+
+/**
+ * Launcher base component for Dagger injection.
+ *
+ * This class is not actually annotated as a Dagger component, since it is not used directly as one.
+ * Doing so generates unnecessary code bloat.
+ *
+ * See {@link LauncherAppComponent} for the one actually used by AOSP.
+ */
+public interface LauncherBaseAppComponent {
+ /** Builder for LauncherBaseAppComponent. */
+ interface Builder {
+ @BindsInstance Builder appContext(@ApplicationContext Context context);
+ LauncherBaseAppComponent build();
+ }
+}
diff --git a/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
index 650df5a..52b454f 100644
--- a/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
+++ b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
@@ -17,6 +17,7 @@
package com.android.launcher3.debug
import android.content.Context
+import android.util.Log
import com.android.launcher3.util.MainThreadInitializedObject
import com.android.launcher3.util.SafeCloseable
@@ -26,6 +27,8 @@
WORKSPACE_ON_DROP("WORKSPACE_ON_DROP"),
RESIZE_FRAME_SHOWING("RESIZE_FRAME_SHOWING"),
WORKSPACE_FINISH_LOADING("WORKSPACE_FINISH_LOADING"),
+ SPRING_LOADED_STATE_STARTED("SPRING_LOADED_STATE_STARTED"),
+ SPRING_LOADED_STATE_COMPLETED("SPRING_LOADED_STATE_COMPLETED"),
}
/** Interface to create TestEventEmitters. */
@@ -50,5 +53,7 @@
override fun close() {}
- override fun sendEvent(event: TestEvent) {}
+ override fun sendEvent(event: TestEvent) {
+ Log.d("TestEventsEmitterProduction", "Event sent ${event.event}")
+ }
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 3edf1f2..7bec768 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -773,6 +773,7 @@
addAnimationStartListeners(anim);
// Because t=0 has the folder match the folder icon, we can skip the
// first frame and have the same movement one frame earlier.
+ Log.d("b/311077782", "Folder.animateOpen");
anim.setCurrentPlayTime(Math.min(getSingleFrameMs(getContext()), anim.getTotalDuration()));
anim.start();
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index a0b695a..de1bcc3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -83,7 +83,7 @@
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
@@ -93,7 +93,7 @@
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
-public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView,
+public class FolderIcon extends FrameLayout implements FolderListener, FloatingIconViewCompanion,
DraggableView, Reorderable {
private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
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/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index dc8694d..374c07b 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -32,6 +32,7 @@
import android.os.IBinder.DeathRecipient;
import android.os.Message;
import android.os.Messenger;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -80,8 +81,10 @@
private static final String KEY_SURFACE_PACKAGE = "surface_package";
private static final String KEY_CALLBACK = "callback";
public static final String KEY_HIDE_BOTTOM_ROW = "hide_bottom_row";
+ public static final String KEY_GRID_NAME = "grid_name";
private static final int MESSAGE_ID_UPDATE_PREVIEW = 1337;
+ private static final int MESSAGE_ID_UPDATE_GRID = 7414;
/**
* Here we use the IBinder and the screen ID as the key of the active previews.
@@ -245,11 +248,22 @@
if (destroyed) {
return true;
}
- if (message.what == MESSAGE_ID_UPDATE_PREVIEW) {
- renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW));
- } else {
- destroyObserver(this);
+
+ switch (message.what) {
+ case MESSAGE_ID_UPDATE_PREVIEW:
+ renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW));
+ break;
+ case MESSAGE_ID_UPDATE_GRID:
+ String gridName = message.getData().getString(KEY_GRID_NAME);
+ if (!TextUtils.isEmpty(gridName)) {
+ renderer.updateGrid(gridName);
+ }
+ break;
+ default:
+ destroyObserver(this);
+ break;
}
+
return true;
}
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index addd072..56c4ca4 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -38,6 +38,7 @@
import android.view.SurfaceControlViewHost.SurfacePackage;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -61,6 +62,7 @@
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
import com.android.launcher3.widget.LocalColorExtractor;
+import com.android.systemui.shared.Flags;
import java.util.ArrayList;
import java.util.Map;
@@ -96,6 +98,7 @@
private boolean mDestroyed = false;
private LauncherPreviewRenderer mRenderer;
private boolean mHideQsb;
+ @Nullable private FrameLayout mViewRoot = null;
public PreviewSurfaceRenderer(Context context, Bundle bundle) throws Exception {
mContext = context;
@@ -194,6 +197,19 @@
}
/**
+ * Update the grid of the launcher preview
+ *
+ * @param gridName Name of the grid, e.g. normal, practical
+ */
+ public void updateGrid(@NonNull String gridName) {
+ if (gridName.equals(mGridName)) {
+ return;
+ }
+ mGridName = gridName;
+ loadAsync();
+ }
+
+ /**
* Hides the components in the bottom row.
*
* @param hide True to hide and false to show.
@@ -302,11 +318,41 @@
view.setPivotY(0);
view.setTranslationX((mWidth - scale * view.getWidth()) / 2);
view.setTranslationY((mHeight - scale * view.getHeight()) / 2);
- view.setAlpha(0);
- view.animate().alpha(1)
- .setInterpolator(new AccelerateDecelerateInterpolator())
- .setDuration(FADE_IN_ANIMATION_DURATION)
- .start();
- mSurfaceControlViewHost.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());
+ if (!Flags.newCustomizationPickerUi()) {
+ view.setAlpha(0);
+ view.animate().alpha(1)
+ .setInterpolator(new AccelerateDecelerateInterpolator())
+ .setDuration(FADE_IN_ANIMATION_DURATION)
+ .start();
+ mSurfaceControlViewHost.setView(
+ view,
+ view.getMeasuredWidth(),
+ view.getMeasuredHeight()
+ );
+ return;
+ }
+
+ if (mViewRoot == null) {
+ mViewRoot = new FrameLayout(inflationContext);
+ FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT, // Width
+ FrameLayout.LayoutParams.WRAP_CONTENT // Height
+ );
+ mViewRoot.setLayoutParams(layoutParams);
+ mViewRoot.addView(view);
+ mViewRoot.setAlpha(0);
+ mViewRoot.animate().alpha(1)
+ .setInterpolator(new AccelerateDecelerateInterpolator())
+ .setDuration(FADE_IN_ANIMATION_DURATION)
+ .start();
+ mSurfaceControlViewHost.setView(
+ mViewRoot,
+ view.getMeasuredWidth(),
+ view.getMeasuredHeight()
+ );
+ } else {
+ mViewRoot.removeAllViews();
+ mViewRoot.addView(view);
+ }
}
}
diff --git a/src/com/android/launcher3/graphics/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java
index 260d490..077ddfc 100644
--- a/src/com/android/launcher3/graphics/SysUiScrim.java
+++ b/src/com/android/launcher3/graphics/SysUiScrim.java
@@ -18,8 +18,6 @@
import static android.graphics.Paint.DITHER_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
-
import android.animation.ObjectAnimator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -111,7 +109,7 @@
new int[]{0x00FFFFFF, 0x2FFFFFFF},
new float[]{0f, 1f});
- if (!KEYGUARD_ANIMATION.get() && !mHideSysUiScrim) {
+ if (!mHideSysUiScrim) {
view.addOnAttachStateChangeListener(this);
}
}
diff --git a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
index 406f697..de2269c 100644
--- a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
+++ b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
@@ -18,10 +18,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherActivityInfo;
+import android.os.Build;
import android.os.UserHandle;
import androidx.annotation.NonNull;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.icons.BaseIconFactory.IconOptions;
@@ -64,9 +66,16 @@
@Override
public BitmapInfo loadIcon(@NonNull Context context, @NonNull LauncherActivityInfo object) {
try (LauncherIcons li = LauncherIcons.obtain(context)) {
- return li.createBadgedIconBitmap(LauncherAppState.getInstance(context)
- .getIconProvider().getIcon(object, li.mFillResIconDpi),
- new IconOptions().setUser(object.getUser()));
+ IconOptions iconOptions = new IconOptions().setUser(object.getUser());
+ iconOptions.mIsArchived = Flags.useNewIconForArchivedApps()
+ && Build.VERSION.SDK_INT >= 35
+ && object.getActivityInfo().isArchived;
+ return li.createBadgedIconBitmap(
+ LauncherAppState.getInstance(context)
+ .getIconProvider()
+ .getIcon(object, li.mFillResIconDpi),
+ iconOptions
+ );
}
}
}
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/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index f54fc57..8d2a7f9 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -121,13 +121,21 @@
@NonNull DeviceGridState destDeviceState,
@NonNull DatabaseHelper target,
@NonNull SQLiteDatabase source) {
+
+ Log.i("b/360462379", "Going from " + srcDeviceState.getColumns() + "x"
+ + srcDeviceState.getRows());
+ Log.i("b/360462379", "Going to " + destDeviceState.getColumns() + "x"
+ + destDeviceState.getRows());
+
if (!needsToMigrate(srcDeviceState, destDeviceState)) {
+ Log.i("b/360462379", "Does not need to migrate.");
return true;
}
if (Flags.enableGridMigrationFix()
&& srcDeviceState.getColumns().equals(destDeviceState.getColumns())
&& srcDeviceState.getRows() < destDeviceState.getRows()) {
+ Log.i("b/360462379", "Grid migration fix entry point.");
// Only use this strategy when comparing the previous grid to the new grid and the
// columns are the same and the destination has more rows
copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 551c2d8..59d1d00 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -192,22 +192,18 @@
}
private void queuePendingShortcutInfo(PendingInstallShortcutInfo info) {
- final Exception stackTrace = new Exception();
// Queue the item up for adding if launcher has not loaded properly yet
MODEL_EXECUTOR.post(() -> {
Pair<ItemInfo, Object> itemInfo = info.getItemInfo(mContext);
if (itemInfo == null) {
FileLog.d(LOG,
- "Adding PendingInstallShortcutInfo with no attached info to queue.",
- stackTrace);
+ "Adding PendingInstallShortcutInfo with no attached info to queue.");
} else {
FileLog.d(LOG,
- "Adding PendingInstallShortcutInfo to queue. Attached info: "
- + itemInfo.first,
- stackTrace);
+ "Adding PendingInstallShortcutInfo to queue."
+ + " Attached info: " + itemInfo.first);
}
-
addToQueue(info);
});
flushInstallQueue();
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 269cb9f..605accf 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -209,7 +209,10 @@
mApp.getContext().getContentResolver(),
"launcher_broadcast_installed_apps",
/* def= */ 0);
- if (launcherBroadcastInstalledApps == 1 && mIsRestoreFromBackup) {
+ boolean shouldAttachArchivingExtras = mIsRestoreFromBackup
+ && (launcherBroadcastInstalledApps == 1
+ || Flags.enableFirstScreenBroadcastArchivingExtras());
+ if (shouldAttachArchivingExtras) {
List<FirstScreenBroadcastModel> broadcastModels =
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
mPmHelper,
diff --git a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
index b12b2bc..2ee5b80 100644
--- a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
+++ b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
@@ -38,6 +38,7 @@
LauncherApps.Callback() {
override fun onPackageAdded(packageName: String, user: UserHandle) {
+ FileLog.d(TAG, "onPackageAdded triggered for packageName=$packageName, user=$user")
taskExecutor.accept(PackageUpdatedTask(OP_ADD, user, packageName))
}
@@ -54,7 +55,7 @@
}
override fun onPackageRemoved(packageName: String, user: UserHandle) {
- FileLog.d(TAG, "package removed received $packageName")
+ FileLog.d(TAG, "onPackageRemoved triggered for packageName=$packageName, user=$user")
taskExecutor.accept(PackageUpdatedTask(OP_REMOVE, user, packageName))
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index b82d0a0..b706d24 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -51,6 +51,7 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logger.LauncherAtom.AllAppsContainer;
+import com.android.launcher3.logger.LauncherAtom.Attribute;
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logger.LauncherAtom.PredictionContainer;
import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
@@ -67,6 +68,9 @@
import com.android.launcher3.util.UserIconInfo;
import com.android.systemui.shared.system.SysUiStatsLog;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Optional;
/**
@@ -77,8 +81,6 @@
public static final boolean DEBUG = false;
public static final int NO_ID = -1;
- // An id that doesn't match any item, including predicted apps with have an id=NO_ID
- public static final int NO_MATCHING_ID = Integer.MIN_VALUE;
/** Hidden field Settings.Secure.NAV_BAR_KIDS_MODE */
private static final Uri NAV_BAR_KIDS_MODE = Settings.Secure.getUriFor("nav_bar_kids_mode");
@@ -187,6 +189,12 @@
@NonNull
public UserHandle user;
+ @NonNull
+ private ExtendedContainers mExtendedContainers = ExtendedContainers.getDefaultInstance();
+
+ @NonNull
+ private List<Attribute> mAttributeList = Collections.EMPTY_LIST;
+
public ItemInfo() {
user = Process.myUserHandle();
}
@@ -433,6 +441,7 @@
UserCache.INSTANCE.executeIfCreated(cache ->
itemBuilder.setUserType(getUserType(cache.getUserInfo(user))));
itemBuilder.setRank(rank);
+ itemBuilder.addAllItemAttributes(mAttributeList);
return itemBuilder;
}
@@ -491,7 +500,7 @@
default:
if (container <= EXTENDED_CONTAINERS) {
return ContainerInfo.newBuilder()
- .setExtendedContainers(getExtendedContainer())
+ .setExtendedContainers(mExtendedContainers)
.build();
}
}
@@ -499,12 +508,21 @@
}
/**
- * Returns non-AOSP container wrapped by {@link ExtendedContainers} object. Should be overridden
- * by build variants.
+ * Sets extra container info wrapped by {@link ExtendedContainers} object.
*/
- @NonNull
- protected ExtendedContainers getExtendedContainer() {
- return ExtendedContainers.getDefaultInstance();
+ public void setExtendedContainers(@NonNull ExtendedContainers extendedContainers) {
+ mExtendedContainers = extendedContainers;
+ }
+
+ /**
+ * Adds extra attributes to be added during logs
+ */
+ public void addLogAttributes(List<LauncherAtom.Attribute> attributeList) {
+ if (mAttributeList.isEmpty()) {
+ mAttributeList = new ArrayList<>(attributeList);
+ } else {
+ mAttributeList.addAll(attributeList);
+ }
}
/**
@@ -525,6 +543,14 @@
this.title = title;
}
+ /**
+ * Returns a string ID that is stable for a user session, but may not be persisted
+ */
+ @Nullable
+ public Object getStableId() {
+ return getComponentKey();
+ }
+
private int getUserType(UserIconInfo info) {
if (info == null) {
return SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_UNKNOWN;
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/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
deleted file mode 100644
index bde4e52..0000000
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package com.android.launcher3.pageindicators;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.AttributeSet;
-import android.util.Property;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.Themes;
-
-/**
- * A PageIndicator that briefly shows a fraction of a line when moving between pages
- *
- * The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
- */
-public class WorkspacePageIndicator extends View implements Insettable, PageIndicator {
-
- private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
- private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
- public static final int WHITE_ALPHA = (int) (0.70f * 255);
- public static final int BLACK_ALPHA = (int) (0.65f * 255);
-
- private static final int LINE_ALPHA_ANIMATOR_INDEX = 0;
- private static final int NUM_PAGES_ANIMATOR_INDEX = 1;
- private static final int TOTAL_SCROLL_ANIMATOR_INDEX = 2;
- private static final int ANIMATOR_COUNT = 3;
-
- private ValueAnimator[] mAnimators = new ValueAnimator[ANIMATOR_COUNT];
-
- private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper());
- private final Launcher mLauncher;
-
- private boolean mShouldAutoHide = true;
-
- // The alpha of the line when it is showing.
- private int mActiveAlpha = 0;
- // The alpha that the line is being animated to or already at (either 0 or mActiveAlpha).
- private int mToAlpha;
- // A float value representing the number of pages, to allow for an animation when it changes.
- private float mNumPagesFloat;
- private int mCurrentScroll;
- private int mTotalScroll;
- private Paint mLinePaint;
- private final int mLineHeight;
-
- private static final Property<WorkspacePageIndicator, Integer> PAINT_ALPHA
- = new Property<WorkspacePageIndicator, Integer>(Integer.class, "paint_alpha") {
- @Override
- public Integer get(WorkspacePageIndicator obj) {
- return obj.mLinePaint.getAlpha();
- }
-
- @Override
- public void set(WorkspacePageIndicator obj, Integer alpha) {
- obj.mLinePaint.setAlpha(alpha);
- obj.invalidate();
- }
- };
-
- private static final Property<WorkspacePageIndicator, Float> NUM_PAGES
- = new Property<WorkspacePageIndicator, Float>(Float.class, "num_pages") {
- @Override
- public Float get(WorkspacePageIndicator obj) {
- return obj.mNumPagesFloat;
- }
-
- @Override
- public void set(WorkspacePageIndicator obj, Float numPages) {
- obj.mNumPagesFloat = numPages;
- obj.invalidate();
- }
- };
-
- private static final Property<WorkspacePageIndicator, Integer> TOTAL_SCROLL
- = new Property<WorkspacePageIndicator, Integer>(Integer.class, "total_scroll") {
- @Override
- public Integer get(WorkspacePageIndicator obj) {
- return obj.mTotalScroll;
- }
-
- @Override
- public void set(WorkspacePageIndicator obj, Integer totalScroll) {
- obj.mTotalScroll = totalScroll;
- obj.invalidate();
- }
- };
-
- private Runnable mHideLineRunnable = () -> animateLineToAlpha(0);
-
- public WorkspacePageIndicator(Context context) {
- this(context, null);
- }
-
- public WorkspacePageIndicator(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public WorkspacePageIndicator(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- Resources res = context.getResources();
- mLinePaint = new Paint();
- mLinePaint.setAlpha(0);
-
- mLauncher = Launcher.getLauncher(context);
- mLineHeight = res.getDimensionPixelSize(R.dimen.workspace_page_indicator_line_height);
-
- boolean darkText = Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText);
- mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
- mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (mTotalScroll == 0 || mNumPagesFloat == 0) {
- return;
- }
-
- // Compute and draw line rect.
- float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f);
- int availableWidth = getWidth();
- int lineWidth = (int) (availableWidth / mNumPagesFloat);
- int lineLeft = (int) (progress * (availableWidth - lineWidth));
- int lineRight = lineLeft + lineWidth;
-
- canvas.drawRoundRect(lineLeft, getHeight() / 2 - mLineHeight / 2, lineRight,
- getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint);
- }
-
- @Override
- public void setScroll(int currentScroll, int totalScroll) {
- if (getAlpha() == 0) {
- return;
- }
- animateLineToAlpha(mActiveAlpha);
-
- mCurrentScroll = currentScroll;
- if (mTotalScroll == 0) {
- mTotalScroll = totalScroll;
- } else if (mTotalScroll != totalScroll) {
- animateToTotalScroll(totalScroll);
- } else {
- invalidate();
- }
-
- if (mShouldAutoHide) {
- hideAfterDelay();
- }
- }
-
- private void hideAfterDelay() {
- mDelayedLineFadeHandler.removeCallbacksAndMessages(null);
- mDelayedLineFadeHandler.postDelayed(mHideLineRunnable, LINE_FADE_DELAY);
- }
-
- @Override
- public void setActiveMarker(int activePage) { }
-
- @Override
- public void setMarkersCount(int numMarkers) {
- if (Float.compare(numMarkers, mNumPagesFloat) != 0) {
- setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numMarkers),
- NUM_PAGES_ANIMATOR_INDEX);
- } else {
- if (mAnimators[NUM_PAGES_ANIMATOR_INDEX] != null) {
- mAnimators[NUM_PAGES_ANIMATOR_INDEX].cancel();
- mAnimators[NUM_PAGES_ANIMATOR_INDEX] = null;
- }
- }
- }
-
- @Override
- public void setShouldAutoHide(boolean shouldAutoHide) {
- mShouldAutoHide = shouldAutoHide;
- if (shouldAutoHide && mLinePaint.getAlpha() > 0) {
- hideAfterDelay();
- } else if (!shouldAutoHide) {
- mDelayedLineFadeHandler.removeCallbacksAndMessages(null);
- }
- }
-
- private void animateLineToAlpha(int alpha) {
- if (alpha == mToAlpha) {
- // Ignore the new animation if it is going to the same alpha as the current animation.
- return;
- }
- mToAlpha = alpha;
- setupAndRunAnimation(ObjectAnimator.ofInt(this, PAINT_ALPHA, alpha),
- LINE_ALPHA_ANIMATOR_INDEX);
- }
-
- private void animateToTotalScroll(int totalScroll) {
- setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll),
- TOTAL_SCROLL_ANIMATOR_INDEX);
- }
-
- /**
- * Starts the given animator and stores it in the provided index in {@link #mAnimators} until
- * the animation ends.
- *
- * If an animator is already at the index (i.e. it is already playing), it is canceled and
- * replaced with the new animator.
- */
- private void setupAndRunAnimation(ValueAnimator animator, final int animatorIndex) {
- if (mAnimators[animatorIndex] != null) {
- mAnimators[animatorIndex].cancel();
- }
- mAnimators[animatorIndex] = animator;
- mAnimators[animatorIndex].addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimators[animatorIndex] = null;
- }
- });
- mAnimators[animatorIndex].setDuration(LINE_ANIMATE_DURATION);
- mAnimators[animatorIndex].start();
- }
-
- /**
- * Pauses all currently running animations.
- */
- @Override
- public void pauseAnimations() {
- for (int i = 0; i < ANIMATOR_COUNT; i++) {
- if (mAnimators[i] != null) {
- mAnimators[i].pause();
- }
- }
- }
-
- /**
- * Force-ends all currently running or paused animations.
- */
- @Override
- public void skipAnimationsToEnd() {
- for (int i = 0; i < ANIMATOR_COUNT; i++) {
- if (mAnimators[i] != null) {
- mAnimators[i].end();
- }
- }
- }
-
- /**
- * We need to override setInsets to prevent InsettableFrameLayout from applying different
- * margins on the page indicator.
- */
- @Override
- public void setInsets(Rect insets) {
- }
-}
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index c117be4..856c294 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -25,6 +25,7 @@
import android.content.pm.PackageInstaller.SessionInfo;
import android.os.Build;
import android.os.UserHandle;
+import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.NonNull;
@@ -32,6 +33,7 @@
import androidx.annotation.WorkerThread;
import com.android.launcher3.Flags;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.PackageUserKey;
import java.lang.ref.WeakReference;
@@ -41,6 +43,8 @@
@WorkerThread
public class InstallSessionTracker extends PackageInstaller.SessionCallback {
+ public static final String TAG = "InstallSessionTracker";
+
// Lazily initialized
private SparseArray<PackageUserKey> mActiveSessions = null;
@@ -75,6 +79,11 @@
}
SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
if (sessionInfo != null) {
+ FileLog.d(TAG, "onCreated: Install session created for"
+ + " appPackageName=" + sessionInfo.getAppPackageName()
+ + ", sessionId=" + sessionInfo.getSessionId()
+ + ", appIcon=" + sessionInfo.getAppIcon()
+ + ", appLabel=" + sessionInfo.getAppLabel());
callback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo));
}
@@ -102,6 +111,10 @@
activeSessions.remove(sessionId);
if (key != null && key.mPackageName != null) {
+ FileLog.d(TAG, "onFinished: active install session finished for"
+ + " appPackageName=" + key.mPackageName
+ + ", sessionId=" + sessionId
+ + ", success=" + success);
String packageName = key.mPackageName;
PackageInstallInfo info = PackageInstallInfo.fromState(
success ? STATUS_INSTALLED : STATUS_FAILED,
@@ -141,6 +154,11 @@
}
SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
if (sessionInfo != null) {
+ Log.d(TAG, "onBadgingChanged: badging info changed for"
+ + " appPackageName=" + sessionInfo.getAppPackageName()
+ + ", sessionId=" + sessionInfo.getSessionId()
+ + ", appIcon=" + sessionInfo.getAppIcon()
+ + ", appLabel=" + sessionInfo.getAppLabel());
helper.tryQueuePromiseAppIcon(sessionInfo);
}
}
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 4d4a8f7..c2debfa 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -16,8 +16,6 @@
package com.android.launcher3.popup;
-import static androidx.core.content.ContextCompat.getColorStateList;
-
import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.app.animation.Interpolators.LINEAR;
@@ -56,8 +54,6 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
-import java.util.Arrays;
-
/**
* A container for shortcuts to deep links and notifications associated with an app.
*
@@ -130,7 +126,7 @@
// Tag for Views that have children that will need to be iterated to add styling.
private final String mIterateChildrenTag;
- protected final int[] mColorIds;
+ protected final int[] mColors;
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -142,8 +138,7 @@
// Initialize arrow view
final Resources resources = getResources();
- mArrowColor = getColorStateList(getContext(), R.color.popup_color_background)
- .getDefaultColor();
+ mArrowColor = Themes.getAttrColor(getContext(), R.attr.materialColorSurfaceContainer);
mChildContainerMargin = resources.getDimensionPixelSize(R.dimen.popup_margin);
mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
@@ -158,21 +153,25 @@
mRoundedTop = new GradientDrawable();
int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
mRoundedTop.setColor(popupPrimaryColor);
- mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
+ mRoundedTop.setCornerRadii(new float[]{mOutlineRadius, mOutlineRadius, mOutlineRadius,
mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
mRoundedBottom = new GradientDrawable();
mRoundedBottom.setColor(popupPrimaryColor);
- mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
+ mRoundedBottom.setCornerRadii(new float[]{smallerRadius, smallerRadius, smallerRadius,
smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
if (mActivityContext.canUseMultipleShadesForPopup()) {
- mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
- R.color.popup_shade_third};
+ mColors = new int[]{
+ getContext().getColor(R.color.popup_shade_first),
+ getContext().getColor(R.color.popup_shade_second),
+ getContext().getColor(R.color.popup_shade_third)
+ };
} else {
- mColorIds = new int[]{R.color.popup_color_background};
+ mColors = new int[]{Themes.getAttrColor(getContext(),
+ R.attr.materialColorSurfaceContainer)};
}
}
@@ -219,15 +218,14 @@
}
/**
- * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColorIds}.
+ * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColors}.
* Otherwise, we will use this color for all child views.
*/
protected void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) {
int[] colors = null;
if (backgroundColor == Color.TRANSPARENT) {
// Lazily get the colors so they match the current wallpaper colors.
- colors = Arrays.stream(mColorIds).map(
- r -> getColorStateList(getContext(), r).getDefaultColor()).toArray();
+ colors = mColors;
}
int count = viewGroup.getChildCount();
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index f7e1168..1b245ab 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -7,13 +7,14 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP;
import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findAllWidgetsForPackageUser;
-import android.app.ActivityOptions;
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 +26,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;
@@ -32,6 +34,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.InstantAppResolver;
@@ -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;
@@ -180,10 +184,12 @@
@Override
public void onClick(View view) {
- dismissTaskMenuView();
Rect sourceBounds = Utilities.getViewBounds(view);
+ ActivityOptionsWrapper options = mTarget.getActivityLaunchOptions(view, mItemInfo);
+ // Dismiss the taskMenu when the app launch animation is complete
+ options.onEndCallback.add(this::dismissTaskMenuView);
PackageManagerHelper.startDetailsActivityForInfo(view.getContext(), mItemInfo,
- sourceBounds, ActivityOptions.makeBasic().toBundle());
+ sourceBounds, options.toBundle());
mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
.log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
}
@@ -383,4 +389,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 78ce3a2..82229f8 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -18,23 +18,18 @@
import android.content.Context
import android.util.Log
-import android.view.ViewGroup
-import androidx.annotation.VisibleForTesting
-import androidx.annotation.VisibleForTesting.Companion.PROTECTED
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
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.ActivityContext.ActivityContextDelegate
-import java.lang.IllegalStateException
const val PREINFLATE_ICONS_ROW_COUNT = 4
const val EXTRA_ICONS_COUNT = 2
@@ -44,11 +39,10 @@
* [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"
@@ -59,7 +53,7 @@
/**
* 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)
@@ -83,7 +77,7 @@
ActivityContextDelegate(
context.createConfigurationContext(context.resources.configuration),
Themes.getActivityThemeRes(context),
- context
+ context,
)
// Because we perform onCreateViewHolder() on worker thread, we need a separate
@@ -96,59 +90,43 @@
context,
context.appsView.layoutInflater.cloneInContext(allAppsPreInflationContext),
null,
- null
+ null,
) {
override fun setAppsPerRow(appsPerRow: Int) = Unit
override fun getLayoutManager(): RecyclerView.LayoutManager? = null
}
- preInflateAllAppsViewHolders(
- adapter,
- BaseAllAppsAdapter.VIEW_TYPE_ICON,
- activeRv,
- preInflateCount
- ) {
- getPreinflateCount(context)
- }
- }
-
- @VisibleForTesting(otherwise = PROTECTED)
- fun preInflateAllAppsViewHolders(
- adapter: RecyclerView.Adapter<*>,
- viewType: Int,
- parent: ViewGroup,
- preInflationCount: Int,
- preInflationCountProvider: () -> Int
- ) {
- 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)
}
/**
@@ -165,18 +143,15 @@
* app icons plus [EXTRA_ICONS_COUNT] is the magic minimal count of app icons to preinflate to
* suffice fast scrolling.
*
- * Note that if [FeatureFlags.ALL_APPS_GONE_VISIBILITY] is enabled, we need to preinfate extra
- * app icons in size of one all apps pages, so that opening all apps don't need to inflate app
- * icons.
+ * Note that we need to preinfate extra 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
- if (FeatureFlags.ALL_APPS_GONE_VISIBILITY.get()) {
- val grid = ActivityContext.lookupContext<T>(context).deviceProfile
- targetPreinflateCount += grid.maxAllAppsRowCount * grid.numShownAllAppsColumns
- }
+ val grid = ActivityContext.lookupContext<T>(context).deviceProfile
+ targetPreinflateCount += grid.maxAllAppsRowCount * grid.numShownAllAppsColumns
if (hasWorkProfile) {
targetPreinflateCount *= 2
}
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index ac07c0f..303290d 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -253,7 +253,7 @@
if (mConfig.currentAnimation == null) {
// Run any queued runnable
if (listener != null) {
- listener.onAnimationEnd(null);
+ listener.onAnimationEnd(new AnimatorSet());
}
return;
} else if ((!mConfig.isUserControlled() && animated && mConfig.targetState == state)
@@ -282,7 +282,7 @@
// Run any queued runnable
if (listener != null) {
- listener.onAnimationEnd(null);
+ listener.onAnimationEnd(new AnimatorSet());
}
return;
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index db2a6e0..6d9b891 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -501,7 +501,7 @@
/**
* Returns the result by getting a generic property on UI thread
*/
- private static <S, T> Bundle getUIProperty(
+ protected static <S, T> Bundle getUIProperty(
BundleSetter<T> bundleSetter, Function<S, T> provider, Supplier<S> targetSupplier) {
return getFromExecutorSync(MAIN_EXECUTOR, () -> {
S target = targetSupplier.get();
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index fe4a83b..9dcdf22 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -22,13 +22,9 @@
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.app.animation.Interpolators.clampToProgress;
-import static com.android.app.animation.Interpolators.mapToProgress;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_BOTTOM_SHEET_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_KEYBOARD_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
@@ -37,15 +33,12 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
-import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import com.android.app.animation.Interpolators;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.states.StateAnimationConfig;
@@ -281,36 +274,6 @@
}
}
- /**
- * Applies Animation config values for transition from overview to all apps.
- *
- * @param threshold progress at which all apps will open upon release
- */
- public static void applyOverviewToAllAppsAnimConfig(
- DeviceProfile deviceProfile, StateAnimationConfig config, float threshold) {
- config.animProps |= StateAnimationConfig.USER_CONTROLLED;
- config.animFlags = SKIP_OVERVIEW;
- if (deviceProfile.isTablet) {
- config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
- config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER);
- // The fact that we end on Workspace is not very ideal, but since we do, fade it in at
- // the end of the transition. Don't scale/translate it.
- config.setInterpolator(ANIM_WORKSPACE_FADE, clampToProgress(LINEAR, 0.8f, 1));
- config.setInterpolator(ANIM_WORKSPACE_SCALE, INSTANT);
- config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, INSTANT);
- } else {
- // Pop the background panel, keyboard, and content in at full opacity at the threshold.
- config.setInterpolator(ANIM_ALL_APPS_BOTTOM_SHEET_FADE,
- thresholdInterpolator(threshold, INSTANT));
- config.setInterpolator(ANIM_ALL_APPS_KEYBOARD_FADE,
- thresholdInterpolator(threshold, INSTANT));
- config.setInterpolator(ANIM_ALL_APPS_FADE, thresholdInterpolator(threshold, INSTANT));
-
- config.setInterpolator(ANIM_VERTICAL_PROGRESS,
- thresholdInterpolator(threshold, mapToProgress(LINEAR, threshold, 1f)));
- }
- }
-
/** Creates an interpolator that is 0 until the threshold, then follows given interpolator. */
private static Interpolator thresholdInterpolator(float threshold, Interpolator interpolator) {
return progress -> progress <= threshold ? 0 : interpolator.getInterpolation(progress);
diff --git a/src/com/android/launcher3/util/ActivityOptionsWrapper.java b/src/com/android/launcher3/util/ActivityOptionsWrapper.java
index 99cc1f7..17ff2a9 100644
--- a/src/com/android/launcher3/util/ActivityOptionsWrapper.java
+++ b/src/com/android/launcher3/util/ActivityOptionsWrapper.java
@@ -25,6 +25,7 @@
public class ActivityOptionsWrapper {
public final ActivityOptions options;
+ // Called when the app launch animation is complete
public final RunnableList onEndCallback;
public ActivityOptionsWrapper(ActivityOptions options, RunnableList onEndCallback) {
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/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index b1e82bb..072bcdf 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -187,11 +187,6 @@
return INSTANCE.get(context).getInfo().isTransientTaskbar();
}
- /** Returns whether we are currently in Desktop mode. */
- public static boolean isInDesktopMode(Context context) {
- return INSTANCE.get(context).getInfo().isInDesktopMode();
- }
-
/**
* Handles info change for desktop mode.
*/
@@ -496,10 +491,6 @@
return navigationMode == NavigationMode.NO_BUTTON && !isTransientTaskbar();
}
- public boolean isInDesktopMode() {
- return mIsInDesktopMode;
- }
-
/**
* Returns {@code true} if the bounds represent a tablet.
*/
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index 1a0f9a0..63f14bd 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -35,6 +35,9 @@
/**
* Utility class for defining singletons which are initiated on main thread.
+ *
+ * TODO(b/361850561): Do not delete MainThreadInitializedObject until we find a way to
+ * unregister and understand how singleton objects are destroyed in dagger graph.
*/
public class MainThreadInitializedObject<T extends SafeCloseable> {
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 8c5a76e..469e363 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -212,7 +212,7 @@
if (info instanceof ItemInfoWithIcon appInfo
&& (appInfo.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
context.startActivity(ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent(
- appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()));
+ appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()), opts);
return;
}
ComponentName componentName = null;
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 837d7bc..f457e4e 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -211,7 +211,7 @@
private Drawable drawable;
public final Intent intent;
public final SplitPositionOption position;
- public final ItemInfo itemInfo;
+ private ItemInfo itemInfo;
public final StatsLogManager.EventEnum splitEvent;
/** Represents the taskId of the first app to start in split screen */
public int alreadyRunningTaskId = INVALID_TASK_ID;
@@ -239,5 +239,9 @@
public View getView() {
return view;
}
+
+ public ItemInfo getItemInfo() {
+ return itemInfo;
+ }
}
}
diff --git a/src/com/android/launcher3/util/StableViewInfo.kt b/src/com/android/launcher3/util/StableViewInfo.kt
new file mode 100644
index 0000000..29dcd59
--- /dev/null
+++ b/src/com/android/launcher3/util/StableViewInfo.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.os.IBinder
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.ItemInfo.NO_ID
+
+/** Info parameters that can be used to identify a Launcher object */
+data class StableViewInfo(val itemId: Int, val containerId: Int, val stableId: Any) {
+
+ fun matches(info: ItemInfo?) =
+ info != null &&
+ itemId == info.id &&
+ containerId == info.container &&
+ stableId == info.stableId
+
+ companion object {
+
+ private fun ItemInfo.toStableViewInfo() =
+ stableId?.let { sId ->
+ if (id != NO_ID || container != NO_ID) StableViewInfo(id, container, sId) else null
+ }
+
+ /**
+ * Return a new launch cookie for the activity launch if supported.
+ *
+ * @param info the item info for the launch
+ */
+ @JvmStatic
+ fun toLaunchCookie(info: ItemInfo?) =
+ info?.toStableViewInfo()?.let { ObjectWrapper.wrap(it) }
+
+ /**
+ * Unwraps the binder and returns the first non-null StableViewInfo in the list or null if
+ * none can be found
+ */
+ @JvmStatic
+ fun fromLaunchCookies(launchCookies: List<IBinder>) =
+ launchCookies.firstNotNullOfOrNull { ObjectWrapper.unwrap<StableViewInfo>(it) }
+ }
+}
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 6bae1ba..a4b8eb0 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -25,12 +25,10 @@
import android.content.Context;
import android.media.AudioAttributes;
import android.net.Uri;
-import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
-import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
@@ -54,20 +52,6 @@
static final Uri HAPTIC_FEEDBACK_URI = Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED);
@VisibleForTesting static final float LOW_TICK_SCALE = 0.9f;
- @VisibleForTesting static final float DRAG_TEXTURE_SCALE = 0.03f;
- @VisibleForTesting static final float DRAG_COMMIT_SCALE = 0.5f;
- @VisibleForTesting static final float DRAG_BUMP_SCALE = 0.4f;
- @VisibleForTesting static final int DRAG_TEXTURE_EFFECT_SIZE = 200;
-
- @Nullable
- private final VibrationEffect mDragEffect;
- @Nullable
- private final VibrationEffect mCommitEffect;
- @Nullable
- private final VibrationEffect mBumpEffect;
-
- private long mLastDragTime;
- private final int mThresholdUntilNextDragCallMillis;
/**
* Haptic when entering overview.
@@ -100,28 +84,6 @@
} else {
mIsHapticFeedbackEnabled = false;
}
-
- if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(
- PRIMITIVE_LOW_TICK)) {
-
- // Drag texture, Commit, and Bump should only be used for premium phones.
- // Before using these haptics make sure check if the device can use it
- mDragEffect = getDragEffect();
- mCommitEffect = VibrationEffect.startComposition().addPrimitive(
- VibrationEffect.Composition.PRIMITIVE_TICK, DRAG_COMMIT_SCALE).compose();
- mBumpEffect = VibrationEffect.startComposition().addPrimitive(
- PRIMITIVE_LOW_TICK, DRAG_BUMP_SCALE).compose();
- int primitiveDuration = mVibrator.getPrimitiveDurations(
- PRIMITIVE_LOW_TICK)[0];
-
- mThresholdUntilNextDragCallMillis =
- DRAG_TEXTURE_EFFECT_SIZE * primitiveDuration + 100;
- } else {
- mDragEffect = null;
- mCommitEffect = null;
- mBumpEffect = null;
- mThresholdUntilNextDragCallMillis = 0;
- }
}
@Override
@@ -132,52 +94,11 @@
}
/**
- * This is called when the user swipes to/from all apps. This is meant to be used in between
- * long animation progresses so that it gives a dragging texture effect. For a better
- * experience, this should be used in combination with vibrateForDragCommit().
- */
- public void vibrateForDragTexture() {
- if (mDragEffect == null) {
- return;
- }
- long currentTime = SystemClock.elapsedRealtime();
- long elapsedTimeSinceDrag = currentTime - mLastDragTime;
- if (elapsedTimeSinceDrag >= mThresholdUntilNextDragCallMillis) {
- vibrate(mDragEffect);
- mLastDragTime = currentTime;
- }
- }
-
- /**
- * This is used when user reaches the commit threshold when swiping to/from from all apps.
- */
- public void vibrateForDragCommit() {
- if (mCommitEffect != null) {
- vibrate(mCommitEffect);
- }
- // resetting dragTexture timestamp to be able to play dragTexture again
- mLastDragTime = 0;
- }
-
- /**
- * The bump haptic is used to be called at the end of a swipe and only if it the gesture is a
- * FLING going to/from all apps. Client can just call this method elsewhere just for the
- * effect.
- */
- public void vibrateForDragBump() {
- if (mBumpEffect != null) {
- vibrate(mBumpEffect);
- }
- }
-
- /**
* This should be used to cancel a haptic in case where the haptic shouldn't be vibrating. For
* example, when no animation is happening but a vibrator happens to be vibrating still.
*/
public void cancelVibrate() {
UI_HELPER_EXECUTOR.execute(mVibrator::cancel);
- // reset dragTexture timestamp to be able to play dragTexture again whenever cancelled
- mLastDragTime = 0;
}
/** Vibrates with the given effect if haptic feedback is available and enabled. */
@@ -217,13 +138,4 @@
vibrate(primitiveLowTickEffect);
}
}
-
- static VibrationEffect getDragEffect() {
- VibrationEffect.Composition dragEffect = VibrationEffect.startComposition();
- for (int i = 0; i < DRAG_TEXTURE_EFFECT_SIZE; i++) {
- dragEffect.addPrimitive(
- PRIMITIVE_LOW_TICK, DRAG_TEXTURE_SCALE);
- }
- return dragEffect.compose();
- }
}
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/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java
index 84f8049..d2ae93b 100644
--- a/src/com/android/launcher3/views/BubbleTextHolder.java
+++ b/src/com/android/launcher3/views/BubbleTextHolder.java
@@ -20,7 +20,7 @@
/**
* Views that contain {@link BubbleTextView} should implement this interface.
*/
-public interface BubbleTextHolder extends IconLabelDotView {
+public interface BubbleTextHolder extends FloatingIconViewCompanion {
BubbleTextView getBubbleText();
@Override
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/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 1e577be..6739387 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -22,7 +22,7 @@
import static com.android.launcher3.Utilities.getFullDrawable;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
import android.animation.Animator;
import android.content.Context;
@@ -175,8 +175,9 @@
mLauncher.getDeviceProfile(), taskViewDrawAlpha);
if (mFadeOutView != null) {
- // The alpha goes from 1 to 0 when progress is 0 and 0.33 respectively.
- mFadeOutView.setAlpha(1 - Math.min(1f, mapToRange(progress, 0, 0.33f, 0, 1, LINEAR)));
+ // The alpha goes from 1 to 0 when progress is 0 and 0.15 respectively.
+ // This value minimizes view display time while still allowing the view to fade out.
+ mFadeOutView.setAlpha(1 - Math.min(1f, mapToRange(progress, 0, 0.15f, 0, 1, LINEAR)));
}
}
@@ -252,11 +253,14 @@
public static void getLocationBoundsForView(Launcher launcher, View v, boolean isOpening,
RectF outRect, Rect outViewBounds) {
boolean ignoreTransform = !isOpening;
- if (v instanceof BubbleTextHolder) {
- v = ((BubbleTextHolder) v).getBubbleText();
+ if (v instanceof DeepShortcutView dsv) {
+ v = dsv.getIconView();
ignoreTransform = false;
- } else if (v.getParent() instanceof DeepShortcutView) {
- v = ((DeepShortcutView) v.getParent()).getIconView();
+ } else if (v.getParent() instanceof DeepShortcutView dsv) {
+ v = dsv.getIconView();
+ ignoreTransform = false;
+ } else if (v instanceof BubbleTextHolder bth) {
+ v = bth.getBubbleText();
ignoreTransform = false;
}
if (v == null) {
@@ -297,10 +301,10 @@
Drawable badge = null;
if (info instanceof SystemShortcut) {
- if (originalView instanceof ImageView) {
- drawable = ((ImageView) originalView).getDrawable();
- } else if (originalView instanceof DeepShortcutView) {
- drawable = ((DeepShortcutView) originalView).getIconView().getBackground();
+ if (originalView instanceof ImageView iv) {
+ drawable = iv.getDrawable();
+ } else if (originalView instanceof DeepShortcutView dsv) {
+ drawable = dsv.getIconView().getBackground();
} else {
drawable = originalView.getBackground();
}
@@ -515,6 +519,10 @@
// When closing an app, we want the item on the workspace to be invisible immediately
updateViewsVisibility(false /* isVisible */);
}
+ if (mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+ fivc.setForceHideDot(true);
+ fivc.setForceHideRing(true);
+ }
}
@Override
@@ -652,6 +660,10 @@
if (view.mFadeOutView != null) {
view.mFadeOutView.setAlpha(1f);
}
+ if (view.mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+ fivc.setForceHideDot(false);
+ fivc.setForceHideRing(false);
+ }
if (hideOriginal) {
view.updateViewsVisibility(true /* isVisible */);
@@ -673,10 +685,10 @@
private void updateViewsVisibility(boolean isVisible) {
if (mOriginalIcon != null) {
- setIconAndDotVisible(mOriginalIcon, isVisible);
+ setPropertiesVisible(mOriginalIcon, isVisible);
}
if (mMatchVisibilityView != null) {
- setIconAndDotVisible(mMatchVisibilityView, isVisible);
+ setPropertiesVisible(mMatchVisibilityView, isVisible);
}
}
diff --git a/src/com/android/launcher3/views/FloatingIconViewCompanion.java b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
new file mode 100644
index 0000000..fc23903
--- /dev/null
+++ b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import android.view.View;
+
+/**
+ * A view that can be drawn (in some capacity) via) {@link FloatingIconView}.
+ * This interface allows us to hide certain properties of the view that the FloatingIconView
+ * cannot draw, which allows us to make a seamless handoff between the FloatingIconView and
+ * the companion view.
+ */
+public interface FloatingIconViewCompanion {
+ void setIconVisible(boolean visible);
+ void setForceHideDot(boolean hide);
+ default void setForceHideRing(boolean hide) {}
+
+ /**
+ * Sets the visibility of icon and dot of the view
+ */
+ static void setPropertiesVisible(View view, boolean visible) {
+ if (view instanceof FloatingIconViewCompanion) {
+ ((FloatingIconViewCompanion) view).setIconVisible(visible);
+ ((FloatingIconViewCompanion) view).setForceHideDot(!visible);
+ ((FloatingIconViewCompanion) view).setForceHideRing(!visible);
+ } else {
+ view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index cab7982..5f8e2c0 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -15,9 +15,8 @@
*/
package com.android.launcher3.views;
-import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
import android.content.Context;
import android.graphics.Canvas;
@@ -160,7 +159,7 @@
if (mContract == null) {
return;
}
- View icon = mLauncher.getFirstMatchForAppClose(NO_MATCHING_ID,
+ View icon = mLauncher.getFirstMatchForAppClose(null /* StableViewInfo */,
mContract.componentName.getPackageName(), mContract.user,
false /* supportsAllAppsState */);
@@ -237,7 +236,7 @@
private void setCurrentIconVisible(boolean isVisible) {
if (mIcon != null) {
- setIconAndDotVisible(mIcon, isVisible);
+ setPropertiesVisible(mIcon, isVisible);
}
}
}
diff --git a/src/com/android/launcher3/views/IconLabelDotView.java b/src/com/android/launcher3/views/IconLabelDotView.java
deleted file mode 100644
index e9113cf..0000000
--- a/src/com/android/launcher3/views/IconLabelDotView.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import android.view.View;
-
-/**
- * A view that has an icon, label, and notification dot.
- */
-public interface IconLabelDotView {
- void setIconVisible(boolean visible);
- void setForceHideDot(boolean hide);
-
- /**
- * Sets the visibility of icon and dot of the view
- */
- static void setIconAndDotVisible(View view, boolean visible) {
- if (view instanceof IconLabelDotView) {
- ((IconLabelDotView) view).setIconVisible(visible);
- ((IconLabelDotView) view).setForceHideDot(!visible);
- } else {
- view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- }
-}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 62eed5c..82cc40d 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.views;
-import static androidx.core.content.ContextCompat.getColorStateList;
-
import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
@@ -147,8 +145,7 @@
@Override
public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
- assignMarginsAndBackgrounds(viewGroup,
- getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
+ assignMarginsAndBackgrounds(viewGroup, mColors[0]);
// last shortcut doesn't need bottom margin
final int count = viewGroup.getChildCount() - 1;
for (int i = 0; i < count; i++) {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index fa17b7b..63648dd 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -20,6 +20,9 @@
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.ALL_APPS_SCROLLER;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.WIDGET_SCROLLER;
+
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -40,11 +43,15 @@
import android.view.WindowInsets;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.FastScrollRecyclerView;
+import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.LetterListTextView;
import com.android.launcher3.graphics.FastScrollThumbDrawable;
import com.android.launcher3.util.Themes;
@@ -55,6 +62,19 @@
* The track and scrollbar that shows when you scroll the list.
*/
public class RecyclerViewFastScroller extends View {
+
+ /** FastScrollerLocation describes what RecyclerView the fast scroller is dedicated to. */
+ public enum FastScrollerLocation {
+ UNKNOWN_SCROLLER(0),
+ ALL_APPS_SCROLLER(1),
+ WIDGET_SCROLLER(2);
+
+ public final int location;
+
+ FastScrollerLocation(int location) {
+ this.location = location;
+ }
+ }
private static final String TAG = "RecyclerViewFastScroller";
private static final boolean DEBUG = false;
private static final int FASTSCROLL_THRESHOLD_MILLIS = 40;
@@ -106,6 +126,8 @@
private final Point mThumbDrawOffset = new Point();
private final Paint mTrackPaint;
+ private final int mThumbColor;
+ private final int mThumbLetterScrollerColor;
private float mLastTouchY;
private boolean mIsDragging;
@@ -139,6 +161,7 @@
private int mDownX;
private int mDownY;
private int mLastY;
+ private FastScrollerLocation mFastScrollerLocation;
public RecyclerViewFastScroller(Context context) {
this(context, null);
@@ -151,13 +174,16 @@
public RecyclerViewFastScroller(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mFastScrollerLocation = FastScrollerLocation.UNKNOWN_SCROLLER;
mTrackPaint = new Paint();
mTrackPaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary));
mTrackPaint.setAlpha(MAX_TRACK_ALPHA);
+ mThumbColor = Themes.getColorAccent(context);
+ mThumbLetterScrollerColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceBright);
mThumbPaint = new Paint();
mThumbPaint.setAntiAlias(true);
- mThumbPaint.setColor(Themes.getColorAccent(context));
+ mThumbPaint.setColor(mThumbColor);
mThumbPaint.setStyle(Paint.Style.FILL);
Resources res = getResources();
@@ -334,6 +360,18 @@
animatePopupVisibility(!TextUtils.isEmpty(sectionName));
mLastTouchY = boundedY;
setThumbOffsetY((int) mLastTouchY);
+ updateFastScrollerLetterList(y);
+ }
+
+ private void updateFastScrollerLetterList(int y) {
+ if (!shouldUseLetterFastScroller()) {
+ return;
+ }
+ ConstraintLayout mLetterList = mRv.getLetterList();
+ for (int i = 0; i < mLetterList.getChildCount(); i++) {
+ LetterListTextView currentLetter = (LetterListTextView) mLetterList.getChildAt(i);
+ currentLetter.animateBasedOnYPosition(y + mTouchOffsetY);
+ }
}
/** End any active fast scrolling touch handling, if applicable. */
@@ -359,15 +397,35 @@
mThumbDrawOffset.set(getWidth() / 2, mRv.getScrollBarTop());
// Draw the track
float halfW = mWidth / 2;
- canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
- mWidth, mWidth, mTrackPaint);
-
- canvas.translate(0, mThumbOffsetY);
+ boolean useLetterFastScroller = shouldUseLetterFastScroller();
+ if (useLetterFastScroller) {
+ float translateX;
+ if (mIsDragging) {
+ // halfW * 3 is half circle.
+ translateX = halfW * 3;
+ } else {
+ translateX = halfW * 5;
+ }
+ canvas.translate(translateX, mThumbOffsetY);
+ } else {
+ canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
+ mWidth, mWidth, mTrackPaint);
+ canvas.translate(0, mThumbOffsetY);
+ }
mThumbDrawOffset.y += mThumbOffsetY;
+
+ /* Draw half circle */
halfW += mThumbPadding;
float r = getScrollThumbRadius();
- mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
- canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
+ if (useLetterFastScroller) {
+ mThumbPaint.setColor(mThumbLetterScrollerColor);
+ mThumbBounds.set(0, 0, 0, mThumbHeight);
+ canvas.drawCircle(-halfW, halfW, r * 2, mThumbPaint);
+ } else {
+ mThumbPaint.setColor(mThumbColor);
+ mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
+ canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
+ }
mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
// swiping very close to the thumb area (not just within it's bound)
// will also prevent back gesture
@@ -380,6 +438,11 @@
canvas.restoreToCount(saveCount);
}
+ boolean shouldUseLetterFastScroller() {
+ return Flags.letterFastScroller()
+ && getScrollerLocation() == FastScrollerLocation.ALL_APPS_SCROLLER;
+ }
+
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mSystemGestureInsets = insets.getSystemGestureInsets();
@@ -421,19 +484,25 @@
return isNearThumb(x, y);
}
- /**
- * Returns whether the specified x position is near the scroll bar.
- */
- public boolean isNearScrollBar(int x) {
- return x >= (getWidth() - mMaxWidth) / 2 - mScrollbarLeftOffsetTouchDelegate
- && x <= (getWidth() + mMaxWidth) / 2;
+ public FastScrollerLocation getScrollerLocation() {
+ return mFastScrollerLocation;
+ }
+
+ public void setFastScrollerLocation(@NonNull FastScrollerLocation location) {
+ mFastScrollerLocation = location;
}
private void animatePopupVisibility(boolean visible) {
if (mPopupVisible != visible) {
mPopupVisible = visible;
- mPopupView.animate().cancel();
- mPopupView.animate().alpha(visible ? 1f : 0f).setDuration(visible ? 200 : 150).start();
+ if (shouldUseLetterFastScroller()) {
+ mRv.getLetterList().animate().alpha(visible ? 1f : 0f)
+ .setDuration(visible ? 200 : 150).start();
+ } else {
+ mPopupView.animate().cancel();
+ mPopupView.animate().alpha(visible ? 1f : 0f)
+ .setDuration(visible ? 200 : 150).start();
+ }
}
}
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/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
index 2e5e251..a2fac46 100644
--- a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
+++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
@@ -29,7 +29,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import java.util.ArrayList;
import java.util.List;
@@ -73,7 +72,7 @@
/** Check if the app widget is in the deny list. */
public static boolean isRoundedCornerEnabled() {
- return Utilities.ATLEAST_S && FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get();
+ return Utilities.ATLEAST_S;
}
/**
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index f332054..352c0a3 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -24,6 +24,8 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.launcher3.icons.RoundDrawableWrapper;
+
/**
* View that draws a bitmap horizontally centered. If the image width is greater than the view
* width, the image is scaled down appropriately.
@@ -85,6 +87,11 @@
final float scale = bitmapAspectRatio > containerAspectRatio ? myWidth / bitmapWidth
: myHeight / bitmapHeight;
+ // When updating the scale, also update scale on drawable if it has rounding.
+ if (mDrawable instanceof RoundDrawableWrapper && scale <= 1) {
+ ((RoundDrawableWrapper) mDrawable).setCornerRadiusScale(scale);
+ }
+
final float scaledWidth = bitmapWidth * scale;
final float scaledHeight = bitmapHeight * scale;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 2af8e6f..c8ad564 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.WIDGET_SCROLLER;
import android.animation.Animator;
import android.content.Context;
@@ -119,7 +120,7 @@
WidgetsRecyclerView searchRecyclerView =
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView;
if (mIsInSearchMode && searchRecyclerView != null) {
- searchRecyclerView.bindFastScrollbar(mFastScroller);
+ searchRecyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
}
}
@@ -276,7 +277,7 @@
}
private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
- recyclerView.bindFastScrollbar(mFastScroller);
+ recyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
if (mCurrentWidgetsRecyclerView != recyclerView) {
// Only reset the scroll position & expanded apps if the currently shown recycler view
// has been updated.
@@ -290,10 +291,10 @@
protected void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
// The first item is always an empty space entry. Look for any more items.
boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
- adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
mNoWidgetsView.setText(R.string.no_search_results);
+ adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
} else if (adapterHolder.mAdapterType == AdapterHolder.WORK
&& mUserCache.getUserProfiles().stream()
.filter(userHandle -> mUserCache.getUserInfo(userHandle).isWork())
@@ -556,6 +557,8 @@
mNoWidgetsView.setVisibility(GONE);
} else {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
+ mAdapters.get(getCurrentAdapterHolderType()).mWidgetsRecyclerView.setVisibility(
+ VISIBLE);
// Visibility of recommended widgets, recycler views and headers are handled in methods
// below.
post(this::onRecommendedWidgetsBound);
@@ -1057,7 +1060,7 @@
mWidgetsRecyclerView.setClipToOutline(true);
mWidgetsRecyclerView.setClipChildren(false);
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
- mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
+ mWidgetsRecyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
mWidgetsRecyclerView.setItemAnimator(isTwoPane() ? null : mWidgetsListItemAnimator);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
if (!isTwoPane()) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index c2cd903..f4b99a0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -27,6 +27,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Process;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -342,14 +343,9 @@
false);
mSuggestedWidgetsHeader.setExpanded(true);
- PackageItemInfo packageItemInfo = new PackageItemInfo(
+ PackageItemInfo packageItemInfo = new HighresPackageItemInfo(
/* packageName= */ SUGGESTIONS_PACKAGE_NAME,
- Process.myUserHandle()) {
- @Override
- public boolean usingLowResIcon() {
- return false;
- }
- };
+ Process.myUserHandle());
String suggestionsHeaderTitle = getContext().getString(
R.string.suggested_widgets_header_title);
String suggestionsRightPaneTitle = getContext().getString(
@@ -376,17 +372,14 @@
mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
final boolean isChangingHeaders = mSelectedHeader == null
|| !mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey);
- // If the initial focus view is still focused, it is likely a programmatic header
- // click.
- if (mSelectedHeader != null
- && !getAccessibilityInitialFocusView().isAccessibilityFocused()) {
- post(() -> {
- mRightPaneScrollView.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
- mRightPaneScrollView.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
- });
- }
if (isChangingHeaders) {
+ // If the initial focus view is still focused or widget picker is still opening, it
+ // is likely a programmatic header click.
+ if (mSelectedHeader != null && !mOpenCloseAnimation.getAnimationPlayer().isRunning()
+ && !getAccessibilityInitialFocusView().isAccessibilityFocused()) {
+ mRightPaneScrollView.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
+ focusOnFirstWidgetCell(mWidgetRecommendationsView);
+ }
// If switching from another header, unselect any WidgetCells. This is necessary
// because we do not clear/recycle the WidgetCells in the recommendations container
// when the header is clicked, only when onRecommendationsBound is called. That
@@ -464,6 +457,13 @@
if (!isWidgetAvailable) {
mRightPane.removeAllViews();
mRightPane.addView(mNoWidgetsView);
+ // with no widgets message, no header is selected on left
+ if (mSuggestedWidgetsPackageUserKey != null
+ && mSuggestedWidgetsPackageUserKey.equals(mSelectedHeader)
+ && mSuggestedWidgetsHeader != null) {
+ mSuggestedWidgetsHeader.setExpanded(false);
+ }
+ mSelectedHeader = null;
}
super.updateRecyclerViewVisibility(adapterHolder);
}
@@ -505,9 +505,10 @@
public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
final boolean isSameHeader = mSelectedHeader != null
&& mSelectedHeader.equals(selectedHeader);
- // If the initial focus view is still focused, it is likely a programmatic header
- // click.
+ // If the initial focus view is still focused or widget picker is still opening, it
+ // is likely a programmatic header click.
final boolean isUserClick = mSelectedHeader != null
+ && !mOpenCloseAnimation.getAnimationPlayer().isRunning()
&& !getAccessibilityInitialFocusView().isAccessibilityFocused();
mSelectedHeader = selectedHeader;
final boolean showDefaultWidgets = mWidgetOptionsMenuState != null
@@ -659,4 +660,15 @@
*/
public boolean showAllWidgets = false;
}
+
+ private static class HighresPackageItemInfo extends PackageItemInfo {
+ HighresPackageItemInfo(String packageName, UserHandle user) {
+ super(packageName, user);
+ }
+
+ @Override
+ public boolean usingLowResIcon() {
+ return false;
+ }
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt
index a016676..1ab8f8b 100644
--- a/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt
+++ b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt
@@ -28,6 +28,7 @@
WidgetPreviewContainerSize(spanX = 2, spanY = 3),
WidgetPreviewContainerSize(spanX = 2, spanY = 2),
WidgetPreviewContainerSize(spanX = 4, spanY = 1),
+ WidgetPreviewContainerSize(spanX = 3, spanY = 1),
WidgetPreviewContainerSize(spanX = 2, spanY = 1),
WidgetPreviewContainerSize(spanX = 1, spanY = 1),
)
diff --git a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
new file mode 100644
index 0000000..63d87e8
--- /dev/null
+++ b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dagger;
+
+import dagger.Component;
+
+/**
+ * Root component for Dagger injection for Launcher AOSP.
+ */
+@LauncherAppSingleton
+@Component
+public interface LauncherAppComponent extends LauncherBaseAppComponent {
+ /** Builder for aosp LauncherAppComponent. */
+ @Component.Builder
+ interface Builder extends LauncherBaseAppComponent.Builder {
+ LauncherAppComponent build();
+ }
+}
+
diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
index a940774..eaa9ef0 100644
--- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
+++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
@@ -49,6 +49,8 @@
default void onActivityDestroyed() { }
+ default void onDisallowSwipeToMinusOnePage() {}
+
/**
* @deprecated use LauncherOverlayTouchProxy directly
*/
diff --git a/tests/Android.bp b/tests/Android.bp
index c99f656..9f62d02 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -127,9 +127,9 @@
"com_android_launcher3_flags_lib",
],
libs: [
- "android.test.base",
- "android.test.runner",
- "android.test.mock",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
+ "android.test.mock.stubs.system",
],
// Libraries used by mockito inline extended
jni_libs: [
@@ -160,7 +160,7 @@
}
filegroup {
- name: "launcher-testing-helpers",
+ name: "launcher-testing-helpers-robo",
srcs: [
"src/**/*.java",
"src/**/*.kt",
@@ -174,11 +174,20 @@
// Test classes
"src/**/*Test.java",
"src/**/*Test.kt",
+ "src/**/RoboApiWrapper.kt",
"multivalentTests/src/**/*Test.java",
"multivalentTests/src/**/*Test.kt",
],
}
+filegroup {
+ name: "launcher-testing-helpers",
+ srcs: [
+ ":launcher-testing-helpers-robo",
+ "src/**/RoboApiWrapper.kt",
+ ],
+}
+
android_robolectric_test {
enabled: true,
name: "Launcher3RoboTests",
@@ -186,7 +195,7 @@
":launcher3-robo-src",
// Test util classes
- ":launcher-testing-helpers",
+ ":launcher-testing-helpers-robo",
":launcher-testing-shared",
],
exclude_srcs: [
@@ -220,9 +229,9 @@
"android.appwidget.flags-aconfig-java",
],
libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
"truth",
],
instrumentation_for: "Launcher3",
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..ea58136 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -148,10 +148,8 @@
public static final String REQUEST_HOTSEAT_CELL_CENTER = "hotseat-cell-center";
- public static final String REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET =
- "get-focused-task-height-for-tablet";
- public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
- "get-grid-task-size-rect-for-tablet";
+ public static final String REQUEST_GET_OVERVIEW_TASK_SIZE = "get-overivew-task-size";
+ public static final String REQUEST_GET_OVERVIEW_GRID_TASK_SIZE = "get-overivew-grid-task-size";
public static final String REQUEST_GET_OVERVIEW_PAGE_SPACING = "get-overview-page-spacing";
public static final String REQUEST_GET_OVERVIEW_CURRENT_PAGE_INDEX =
"get-overview-current-page-index";
@@ -173,8 +171,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/allapps/FloatingHeaderViewTests.kt b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt
similarity index 98%
rename from tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt
rename to tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt
index ac2c553..d2103ae 100644
--- a/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt
@@ -31,7 +31,7 @@
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-class FloatingHeaderViewTests {
+class FloatingHeaderViewTest {
@get:Rule val mSetFlagsRule = SetFlagsRule()
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index 30953cc..a62258c 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -17,6 +17,9 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -37,6 +40,8 @@
import com.android.launcher3.celllayout.testgenerator.RandomBoardGenerator;
import com.android.launcher3.celllayout.testgenerator.RandomMultiBoardGenerator;
import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
import org.junit.Rule;
@@ -68,12 +73,16 @@
private Context mApplicationContext;
@Rule
+ public TestStabilityRule mTestStabilityRule = new TestStabilityRule();
+
+ @Rule
public UnitTestCellLayoutBuilderRule mCellLayoutBuilder = new UnitTestCellLayoutBuilderRule();
/**
* This test reads existing test cases and makes sure the CellLayout produces the same
* output for each of them for a given input.
*/
+ @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
@Test
public void testAllCases() throws IOException {
List<ReorderAlgorithmUnitTestCase> testCases = getTestCases(
@@ -116,6 +125,7 @@
/**
* Same as above but testing the Multipage CellLayout.
*/
+ @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
@Test
public void generateValidTests_Multi() {
Random generator = new Random(SEED);
diff --git a/tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
diff --git a/tests/src/com/android/launcher3/folder/FolderPagedViewTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
diff --git a/tests/src/com/android/launcher3/folder/FolderTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
diff --git a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
rename to tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
index 7242e9c..b9b7d6a 100644
--- a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
@@ -24,15 +24,15 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.PathInterpolator;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.CellLayout;
+import com.android.launcher3.util.LauncherMultivalentJUnit;
import org.junit.Before;
import org.junit.Test;
@@ -41,8 +41,8 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@UiThreadTest
+@RunWith(LauncherMultivalentJUnit.class)
public class PreviewBackgroundTest {
private static final float REST_SCALE = 1f;
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
similarity index 81%
rename from tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 5516f45..d236551 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -25,18 +25,27 @@
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.ModelTestRule
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.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,6 +54,8 @@
@RunWith(AndroidJUnit4::class)
class PreviewItemManagerTest {
+ @get:Rule val modelTestRule = ModelTestRule()
+
private lateinit var previewItemManager: PreviewItemManager
private lateinit var context: Context
private lateinit var folderItems: ArrayList<ItemInfo>
@@ -219,6 +230,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/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/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 370af0c..43dc36b 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -27,6 +27,7 @@
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.times
@@ -43,6 +44,8 @@
@RunWith(AndroidJUnit4::class)
class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
+ @get:Rule val modelTestRule = ModelTestRule()
+
private lateinit var mDataModelCallbacks: MyCallbacks
private val mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder = mock()
diff --git a/tests/src/com/android/launcher3/model/AsyncBindingTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
similarity index 99%
rename from tests/src/com/android/launcher3/model/AsyncBindingTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
index af367a8..dce75b9 100644
--- a/tests/src/com/android/launcher3/model/AsyncBindingTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
@@ -64,6 +64,8 @@
@get:Rule val setFlagsRule = SetFlagsRule()
+ @get:Rule val modelTestRule = ModelTestRule()
+
@Spy private var callbacks = MyCallbacks()
@Mock private lateinit var itemInflater: ItemInflater<*>
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
similarity index 84%
rename from tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 328558d..535080a 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.launcher3.model;
import static android.os.Process.myUserHandle;
@@ -11,10 +26,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
+import android.content.pm.PackageInstaller;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -49,6 +67,9 @@
@Rule(order = 0)
public TestRule testStabilityRule = new TestStabilityRule();
+ @Rule(order = 1)
+ public ModelTestRule mModelTestRule = new ModelTestRule();
+
private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
@@ -128,10 +149,13 @@
@Test
public void testSessionUpdate_updates_pending_apps() {
// Run on model executor so that no other task runs in the middle.
+ PackageInstaller.SessionInfo sessionInfo = ApplicationProvider.getApplicationContext()
+ .getPackageManager().getPackageInstaller().getSessionInfo(mSession1);
+ assertNotNull(sessionInfo);
runOnExecutorSync(MODEL_EXECUTOR, () -> {
LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
new PackageUserKey(PENDING_APP_1, myUserHandle()),
- mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession1));
+ sessionInfo);
// Clear all icons from apps list so that its easy to check what was updated
allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
similarity index 93%
rename from tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 10785f7..e14e145 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -22,11 +22,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -39,6 +39,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,8 +50,10 @@
@RunWith(AndroidJUnit4.class)
public class DefaultLayoutProviderTest {
+ @Rule public ModelTestRule rule = new ModelTestRule();
+
private LauncherModelHelper mModelHelper;
- private Context mTargetContext;
+ private LauncherModelHelper.SandboxModelContext mTargetContext;
@Before
public void setUp() {
@@ -114,8 +117,10 @@
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(pendingAppPkg);
params.setAppIcon(BitmapInfo.LOW_RES_ICON);
+ params.installerPackageName = ApplicationProvider.getApplicationContext().getPackageName();
- PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller();
+ PackageInstaller installer = ApplicationProvider.getApplicationContext().getPackageManager()
+ .getPackageInstaller();
installer.createSession(params);
writeLayoutAndLoad(new LauncherLayoutBuilder().atWorkspace(0, 1, 0)
diff --git a/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
index aadf72e..d2d9512 100644
--- a/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
@@ -21,6 +21,7 @@
import android.content.Intent
import android.content.pm.PackageInstaller.SessionInfo
import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
@@ -33,14 +34,20 @@
import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
import junit.framework.Assert.assertEquals
+import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
+@RunWith(AndroidJUnit4::class)
class FirstScreenBroadcastHelperTest {
+
+ @get:Rule val modelTestRule = ModelTestRule()
+
private val context = spy(InstrumentationRegistry.getInstrumentation().targetContext)
private val mockPmHelper = mock<PackageManagerHelper>()
private val expectedAppPackage = "appPackageExpected"
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
similarity index 96%
rename from tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index c4a4c9b..d002493 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -23,12 +23,14 @@
import com.android.launcher3.util.LauncherLayoutBuilder
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.LauncherModelHelper.*
+import com.android.launcher3.util.RoboApiWrapper
import com.android.launcher3.util.TestUtil
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.concurrent.CountDownLatch
import org.junit.After
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,6 +38,9 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class FolderIconLoadTest {
+
+ @get:Rule(order = 0) val modelTestRule = ModelTestRule()
+
private lateinit var modelHelper: LauncherModelHelper
private val uniqueActivities =
@@ -145,6 +150,7 @@
while (cache.isIconUpdateInProgress) {
val wait = CountDownLatch(1)
Executors.MODEL_EXECUTOR.handler.postDelayed({ wait.countDown() }, 10)
+ RoboApiWrapper.waitForLooperSync(Executors.MODEL_EXECUTOR.handler.looper)
wait.await()
}
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { cache.clearMemoryCache() }
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/model/LoaderCursorTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
index b4945d7..ac911b3 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -67,6 +67,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -77,6 +78,8 @@
@RunWith(AndroidJUnit4.class)
public class LoaderCursorTest {
+ @Rule public ModelTestRule rule = new ModelTestRule();
+
private LauncherModelHelper mModelHelper;
private LauncherAppState mApp;
private PackageManagerHelper mPmHelper;
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt b/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt
new file mode 100644
index 0000000..ad2c2a4
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.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.model
+
+import com.android.launcher3.util.RoboApiWrapper
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+
+class ModelTestRule : TestWatcher() {
+ override fun starting(description: Description?) {
+ RoboApiWrapper.initialize()
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
similarity index 87%
rename from tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index 4ba61ac..a0d9da9 100644
--- a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.launcher3.model;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -22,6 +37,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,6 +48,8 @@
@RunWith(AndroidJUnit4.class)
public class PackageInstallStateChangedTaskTest {
+ @Rule public ModelTestRule mModelTestRule = new ModelTestRule();
+
private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
similarity index 81%
rename from tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 6cf3b19..1d9c161 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -25,10 +25,9 @@
import android.content.pm.ShortcutInfo
import android.os.Process
import android.os.UserHandle
-import android.platform.test.annotations.EnableFlags
import android.util.LongSparseArray
-import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
@@ -36,7 +35,6 @@
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
-import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_INFO
@@ -46,7 +44,6 @@
import com.android.launcher3.model.data.IconRequestInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo
-import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.pm.UserCache
@@ -57,11 +54,12 @@
import com.android.launcher3.util.UserIconInfo
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
import com.android.launcher3.widget.WidgetInflater
-import com.android.launcher3.widget.WidgetSections
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.RETURNS_DEEP_STUBS
@@ -74,10 +72,12 @@
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
-import org.mockito.quality.Strictness
+@RunWith(AndroidJUnit4::class)
class WorkspaceItemProcessorTest {
+ @get:Rule val modelTestRule = ModelTestRule()
+
@Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
@Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
@Mock private lateinit var mockBgDataModel: BgDataModel
@@ -122,6 +122,7 @@
mock<Context>().apply {
whenever(packageManager).thenReturn(mock())
whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
+ whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
}
mockAppState =
mock<LauncherAppState>().apply {
@@ -666,142 +667,6 @@
}
@Test
- fun `When Pending App Widget has not started restore then update db and add item`() {
-
- val mockitoSession =
- ExtendedMockito.mockitoSession()
- .strictness(Strictness.LENIENT)
- .mockStatic(WidgetSections::class.java)
- .startMocking()
- try {
- // Given
- val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
- val expectedComponentName =
- ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
- val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
- val expectedAppWidgetId = 0
- mockCursor.apply {
- itemType = ITEM_TYPE_APPWIDGET
- user = mUserHandle
- restoreFlag = FLAG_UI_NOT_READY
- container = CONTAINER_DESKTOP
- whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
- whenever(appWidgetProvider).thenReturn(expectedProvider)
- whenever(appWidgetId).thenReturn(expectedAppWidgetId)
- whenever(spanX).thenReturn(2)
- whenever(spanY).thenReturn(1)
- whenever(options).thenReturn(0)
- whenever(appWidgetSource).thenReturn(20)
- whenever(applyCommonProperties(any())).thenCallRealMethod()
- whenever(
- updater()
- .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
- .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
- .put(Favorites.RESTORED, expectedRestoreStatus)
- .commit()
- )
- .thenReturn(1)
- }
- val inflationResult =
- WidgetInflater.InflationResult(
- type = WidgetInflater.TYPE_PENDING,
- widgetInfo = null
- )
- mockWidgetInflater =
- mock<WidgetInflater>().apply {
- whenever(inflateAppWidget(any())).thenReturn(inflationResult)
- }
- val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
- mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
-
- // When
- itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
- itemProcessorUnderTest.processItem()
-
- // Then
- val expectedWidgetInfo =
- LauncherAppWidgetInfo().apply {
- appWidgetId = expectedAppWidgetId
- providerName = ComponentName.unflattenFromString(expectedProvider)
- restoreStatus = expectedRestoreStatus
- }
- verify(
- mockCursor
- .updater()
- .put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
- .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
- .put(Favorites.RESTORED, expectedRestoreStatus)
- )
- .commit()
- val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
- verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
- val actualWidgetInfo = widgetInfoCaptor.value
- with(actualWidgetInfo) {
- assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
- assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
- assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
- assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
- }
- } finally {
- mockitoSession.finishMocking()
- }
- }
-
- @Test
- @EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
- fun `When Archived Pending App Widget then checkAndAddItem`() {
- val mockitoSession =
- ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
- try {
- // Given
- val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
- val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
- val expectedPackage = expectedComponentName!!.packageName
- mockPmHelper =
- mock<PackageManagerHelper>().apply {
- whenever(isAppArchived(expectedPackage)).thenReturn(true)
- }
- mockCursor =
- mock<LoaderCursor>().apply {
- itemType = ITEM_TYPE_APPWIDGET
- id = 1
- user = UserHandle(1)
- restoreFlag = FLAG_UI_NOT_READY
- container = CONTAINER_DESKTOP
- whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
- whenever(appWidgetProvider).thenReturn(expectedProvider)
- whenever(appWidgetId).thenReturn(0)
- whenever(spanX).thenReturn(2)
- whenever(spanY).thenReturn(1)
- whenever(options).thenReturn(0)
- whenever(appWidgetSource).thenReturn(20)
- whenever(applyCommonProperties(any())).thenCallRealMethod()
- }
- mInstallingPkgs = hashMapOf()
- val inflationResult =
- WidgetInflater.InflationResult(
- type = WidgetInflater.TYPE_PENDING,
- widgetInfo = null
- )
- mockWidgetInflater =
- mock<WidgetInflater>().apply {
- whenever(inflateAppWidget(any())).thenReturn(inflationResult)
- }
- itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
-
- // When
- itemProcessorUnderTest.processItem()
-
- // Then
- verify(mockCursor).checkAndAddItem(any(), any())
- } finally {
- mockitoSession.finishMocking()
- }
- }
-
- @Test
fun `When widget inflation result is TYPE_DELETE then mark deleted`() {
// Given
val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
index b3d02be..ae8e966 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
@@ -21,6 +21,7 @@
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,6 +30,8 @@
@RunWith(AndroidJUnit4::class)
class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
+ @get:Rule val modelTestRule = ModelTestRule()
+
private val mItemSpaceFinder = WorkspaceItemSpaceFinder()
@Before
diff --git a/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt b/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
similarity index 94%
rename from tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
index b531adb..d860710 100644
--- a/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
@@ -26,6 +26,7 @@
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import com.android.launcher3.model.ModelTestRule
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.PackageUserKey
@@ -35,6 +36,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
+import org.mockito.kotlin.doNothing
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
@@ -43,7 +45,9 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class InstallSessionTrackerTest {
- @get:Rule val setFlagsRule = SetFlagsRule()
+ @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+
+ @get:Rule(order = 1) val modelTestRule = ModelTestRule()
private val mockInstallSessionHelper: InstallSessionHelper = mock()
private val mockCallback: InstallSessionTracker.Callback = mock()
@@ -200,13 +204,9 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
fun `register triggers registerPackageInstallerSessionCallback for versions from Q`() {
// Given
- whenever(
- launcherApps.registerPackageInstallerSessionCallback(
- MODEL_EXECUTOR,
- installSessionTracker
- )
- )
- .then { /* no-op */ }
+ doNothing()
+ .whenever(launcherApps)
+ .registerPackageInstallerSessionCallback(MODEL_EXECUTOR, installSessionTracker)
// When
installSessionTracker.register()
// Then
@@ -218,8 +218,9 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
fun `unregister triggers unregisterPackageInstallerSessionCallback for versions from Q`() {
// Given
- whenever(launcherApps.unregisterPackageInstallerSessionCallback(installSessionTracker))
- .then { /* no-op */ }
+ doNothing()
+ .whenever(launcherApps)
+ .unregisterPackageInstallerSessionCallback(installSessionTracker)
// When
installSessionTracker.unregister()
// Then
diff --git a/tests/src/com/android/launcher3/pm/UserCacheTest.kt b/tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
similarity index 97%
rename from tests/src/com/android/launcher3/pm/UserCacheTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
index b21219e..482dced 100644
--- a/tests/src/com/android/launcher3/pm/UserCacheTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
@@ -20,6 +20,7 @@
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.model.ModelTestRule
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.TestUtil
@@ -27,11 +28,15 @@
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class UserCacheTest {
+
+ @get:Rule val modelTestRule = ModelTestRule()
+
private val launcherModelHelper = LauncherModelHelper()
private val sandboxContext = launcherModelHelper.sandboxContext
private lateinit var userCache: UserCache
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 3e6aae2..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) { 10 }
-
- awaitTasksCompleted()
- assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(10)
- }
-
- @Test
- fun preinflate_not_triggered() {
- underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 0) { 0 }
-
- awaitTasksCompleted()
- assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
- }
-
- @Test
- fun preinflate_cancel_before_runOnMainThread() {
- underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 10) { 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) { 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/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java b/tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
deleted file mode 100644
index 10e0be8..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.settings;
-
-import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT;
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem;
-import static androidx.test.espresso.intent.Intents.intended;
-import static androidx.test.espresso.intent.matcher.BundleMatchers.hasEntry;
-import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
-import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
-import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
-import static androidx.test.espresso.matcher.ViewMatchers.withText;
-
-import static com.android.launcher3.settings.SettingsActivity.DEVELOPER_OPTIONS_KEY;
-import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ARGS;
-import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ROOT_KEY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.equalTo;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.espresso.intent.Intents;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.launcher3.R;
-import com.android.systemui.shared.plugins.PluginPrefs;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class SettingsActivityTest {
-
- private Context mApplicationContext;
-
- @Before
- public void setUp() {
- mApplicationContext = ApplicationProvider.getApplicationContext();
- Intents.init();
- }
-
- @After
- public void tearDown() {
- Intents.release();
- }
-
- @Test
- @Ignore // b/199309785
- public void testSettings_aboutTap_launchesActivity() {
- ActivityScenario.launch(SettingsActivity.class);
- onView(withId(R.id.recycler_view)).perform(
- actionOnItem(hasDescendant(withText("About")), click()));
-
- intended(allOf(
- hasComponent(SettingsActivity.class.getName()),
- hasExtra(
- equalTo(EXTRA_FRAGMENT_ARGS),
- hasEntry(ARG_PREFERENCE_ROOT, "about_screen"))));
- }
-
- @Test
- @Ignore // b/199309785
- public void testSettings_developerOptionsTap_launchesActivityWithFragment() {
- PluginPrefs.setHasPlugins(mApplicationContext);
- ActivityScenario.launch(SettingsActivity.class);
- onView(withId(R.id.recycler_view)).perform(
- actionOnItem(hasDescendant(withText("Developer Options")), click()));
-
- intended(allOf(
- hasComponent(SettingsActivity.class.getName()),
- hasExtra(EXTRA_FRAGMENT_ROOT_KEY, DEVELOPER_OPTIONS_KEY)));
- }
-
- @Test
- @Ignore // b/199309785
- public void testSettings_aboutScreenIntent() {
- Bundle fragmentArgs = new Bundle();
- fragmentArgs.putString(ARG_PREFERENCE_ROOT, "about_screen");
-
- Intent intent = new Intent(mApplicationContext, SettingsActivity.class)
- .putExtra(EXTRA_FRAGMENT_ARGS, fragmentArgs);
- ActivityScenario.launch(intent);
-
- onView(withText("About")).check(matches(isDisplayed()));
- onView(withText("Version")).check(matches(isDisplayed()));
- onView(withContentDescription("Navigate up")).check(matches(isDisplayed()));
- }
-
- @Test
- @Ignore // b/199309785
- public void testSettings_developerOptionsFragmentIntent() {
- Intent intent = new Intent(mApplicationContext, SettingsActivity.class)
- .putExtra(EXTRA_FRAGMENT_ROOT_KEY, DEVELOPER_OPTIONS_KEY);
- ActivityScenario.launch(intent);
-
- onView(withText("Developer Options")).check(matches(isDisplayed()));
- onView(withId(R.id.filter_box)).check(matches(isDisplayed()));
- onView(withContentDescription("Navigate up")).check(matches(isDisplayed()));
- }
-
- @Test
- @Ignore // b/199309785
- public void testSettings_backButtonFinishesActivity() {
- Bundle fragmentArgs = new Bundle();
- fragmentArgs.putString(ARG_PREFERENCE_ROOT, "about_screen");
- Intent intent = new Intent(mApplicationContext, SettingsActivity.class)
- .putExtra(EXTRA_FRAGMENT_ARGS, fragmentArgs);
- ActivityScenario<SettingsActivity> scenario = ActivityScenario.launch(intent);
-
- onView(withContentDescription("Navigate up")).perform(click());
- scenario.onActivity(activity -> assertThat(activity.isFinishing()).isTrue());
- }
-}
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 aa7f388..b933ed2 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -26,6 +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_SUPPORT_FOR_ARCHIVING;
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,7 +417,7 @@
assertThat(mBubbleTextView.getIcon().hasBadge()).isEqualTo(false);
}
- @EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
+ @EnableFlags({FLAG_ENABLE_SUPPORT_FOR_ARCHIVING, FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS})
@Test
public void applyIconAndLabel_setsImageSpan_whenInactiveArchivedApp() {
// Given
@@ -452,7 +453,7 @@
assertThat(actualSpan.getVerticalAlignment()).isEqualTo(ALIGN_CENTER);
}
- @EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
+ @EnableFlags({FLAG_ENABLE_SUPPORT_FOR_ARCHIVING, 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/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index f18c02b..2d53e29 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -45,21 +45,24 @@
import android.util.ArrayMap;
import androidx.test.core.app.ApplicationProvider;
-import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.testing.TestInformationProvider;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
+import java.util.Arrays;
+import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@@ -85,6 +88,23 @@
public static final String TEST_ACTIVITY13 = "com.android.launcher3.tests.Activity14";
public static final String TEST_ACTIVITY14 = "com.android.launcher3.tests.Activity15";
+ public static final List<String> ACTIVITY_LIST = Arrays.asList(
+ TEST_ACTIVITY,
+ TEST_ACTIVITY2,
+ TEST_ACTIVITY3,
+ TEST_ACTIVITY4,
+ TEST_ACTIVITY5,
+ TEST_ACTIVITY6,
+ TEST_ACTIVITY7,
+ TEST_ACTIVITY8,
+ TEST_ACTIVITY9,
+ TEST_ACTIVITY10,
+ TEST_ACTIVITY11,
+ TEST_ACTIVITY12,
+ TEST_ACTIVITY13,
+ TEST_ACTIVITY14
+ );
+
// Authority for providing a test default-workspace-layout data.
private static final String TEST_PROVIDER_AUTHORITY =
LauncherModelHelper.class.getName().toLowerCase();
@@ -128,7 +148,9 @@
icon.eraseColor(Color.RED);
sp.setAppIcon(icon);
sp.setAppLabel(pkg);
- PackageInstaller pi = sandboxContext.getPackageManager().getPackageInstaller();
+ sp.setInstallerPackageName(ApplicationProvider.getApplicationContext().getPackageName());
+ PackageInstaller pi = ApplicationProvider.getApplicationContext().getPackageManager()
+ .getPackageInstaller();
int sessionId = pi.createSession(sp);
mDestroyTask.add(() -> pi.abandonSession(sessionId));
return sessionId;
@@ -164,11 +186,19 @@
public LauncherModelHelper setupDefaultLayoutProvider(LauncherLayoutBuilder builder)
throws Exception {
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(sandboxContext);
- idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE;
- idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
+ if (idp.numRows == 0 && idp.numColumns == 0) {
+ idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE;
+ }
+ if (idp.iconBitmapSize == 0) {
+ idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
+ }
- UiDevice.getInstance(getInstrumentation()).executeShellCommand(
- "settings put secure launcher3.layout.provider " + TEST_PROVIDER_AUTHORITY);
+ Settings.Secure.putString(sandboxContext.getContentResolver(), "launcher3.layout.provider",
+ TEST_PROVIDER_AUTHORITY);
+
+ // TODO: use a wrapper class to differentiate the behavior
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ builder.build(new OutputStreamWriter(bos));
ContentProvider cp = new TestInformationProvider() {
@Override
@@ -177,8 +207,6 @@
try {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
AutoCloseOutputStream outputStream = new AutoCloseOutputStream(pipe[1]);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- builder.build(new OutputStreamWriter(bos));
outputStream.write(bos.toByteArray());
outputStream.flush();
outputStream.close();
@@ -189,9 +217,13 @@
}
};
setupProvider(TEST_PROVIDER_AUTHORITY, cp);
+ RoboApiWrapper.INSTANCE.registerInputStream(sandboxContext.getContentResolver(),
+ ModelDbController.getLayoutUri(TEST_PROVIDER_AUTHORITY, sandboxContext),
+ ()-> new ByteArrayInputStream(bos.toByteArray()));
+
mDestroyTask.add(() -> runOnExecutorSync(MODEL_EXECUTOR, () ->
- UiDevice.getInstance(getInstrumentation()).executeShellCommand(
- "settings delete secure launcher3.layout.provider")));
+ Settings.Secure.putString(sandboxContext.getContentResolver(),
+ "launcher3.layout.provider", "")));
return this;
}
@@ -203,7 +235,7 @@
MAIN_EXECUTOR.submit(() -> getModel().addCallbacksAndLoad(mockCb)).get();
Executors.MODEL_EXECUTOR.submit(() -> { }).get();
- MAIN_EXECUTOR.submit(() -> { }).get();
+ getInstrumentation().waitForIdleSync();
MAIN_EXECUTOR.submit(() -> getModel().removeCallbacks(mockCb)).get();
}
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/util/VibratorWrapperTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
index 330c394..d321e41 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
@@ -17,7 +17,6 @@
package com.android.launcher3.util
import android.media.AudioAttributes
-import android.os.SystemClock
import android.os.VibrationEffect
import android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK
import android.os.VibrationEffect.Composition.PRIMITIVE_TICK
@@ -35,13 +34,11 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.any
-import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.never
import org.mockito.kotlin.same
-import org.mockito.kotlin.verifyNoMoreInteractions
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -118,55 +115,6 @@
}
@Test
- fun vibrate_for_drag_bump() {
- underTest.vibrateForDragBump()
-
- awaitTasksCompleted()
- verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
- val expectedEffect =
- VibrationEffect.startComposition()
- .addPrimitive(PRIMITIVE_LOW_TICK, VibratorWrapper.DRAG_BUMP_SCALE)
- .compose()
- assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
- }
-
- @Test
- fun vibrate_for_drag_commit() {
- underTest.vibrateForDragCommit()
-
- awaitTasksCompleted()
- verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
- val expectedEffect =
- VibrationEffect.startComposition()
- .addPrimitive(PRIMITIVE_TICK, VibratorWrapper.DRAG_COMMIT_SCALE)
- .compose()
- assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
- }
-
- @Test
- fun vibrate_for_drag_texture() {
- SystemClock.setCurrentTimeMillis(40000)
-
- underTest.vibrateForDragTexture()
-
- awaitTasksCompleted()
- verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
- assertThat(vibrationEffectCaptor.value).isEqualTo(VibratorWrapper.getDragEffect())
- }
-
- @Test
- fun vibrate_for_drag_texture_within_time_window_noOp() {
- SystemClock.setCurrentTimeMillis(40000)
- underTest.vibrateForDragTexture()
- awaitTasksCompleted()
- reset(vibrator)
-
- underTest.vibrateForDragTexture()
-
- verifyNoMoreInteractions(vibrator)
- }
-
- @Test
fun haptic_feedback_disabled_no_vibrate() {
`when`(vibrator.hasVibrator()).thenReturn(false)
underTest = VibratorWrapper(vibrator, settingsCache)
diff --git a/tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
similarity index 86%
rename from tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
index 011d138..d26c4d4 100644
--- a/tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
@@ -32,7 +32,7 @@
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.reset
import org.mockito.kotlin.same
-import org.mockito.kotlin.verifyZeroInteractions
+import org.mockito.kotlin.verifyNoMoreInteractions
@RunWith(AndroidJUnit4::class)
class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
@@ -77,8 +77,8 @@
underTest.attachTo(launcher)
verify(workspace).addOnAttachStateChangeListener(same(underTest))
- verifyZeroInteractions(viewTreeObserver)
- verifyZeroInteractions(rootView)
+ verifyNoMoreInteractions(viewTreeObserver)
+ verifyNoMoreInteractions(rootView)
}
@Test
@@ -100,8 +100,8 @@
underTest.onViewAttachedToWindow(rootView)
- verifyZeroInteractions(viewTreeObserver)
- verifyZeroInteractions(rootView)
+ verifyNoMoreInteractions(viewTreeObserver)
+ verifyNoMoreInteractions(rootView)
}
@Test
@@ -117,10 +117,10 @@
fun run_before_onDraw_noOp() {
underTest.run()
- verifyZeroInteractions(runnable)
- verifyZeroInteractions(viewTreeObserver)
- verifyZeroInteractions(workspace)
- verifyZeroInteractions(consumer)
+ verifyNoMoreInteractions(runnable)
+ verifyNoMoreInteractions(viewTreeObserver)
+ verifyNoMoreInteractions(workspace)
+ verifyNoMoreInteractions(consumer)
}
@Test
@@ -148,10 +148,10 @@
underTest.run()
- verifyZeroInteractions(runnable)
- verifyZeroInteractions(viewTreeObserver)
- verifyZeroInteractions(workspace)
- verifyZeroInteractions(consumer)
+ verifyNoMoreInteractions(runnable)
+ verifyNoMoreInteractions(viewTreeObserver)
+ verifyNoMoreInteractions(workspace)
+ verifyNoMoreInteractions(consumer)
}
@Test
@@ -160,7 +160,7 @@
verify(runnable).run()
verify(consumer).accept(underTest)
- verifyZeroInteractions(workspace)
+ verifyNoMoreInteractions(workspace)
}
@Test
@@ -179,8 +179,8 @@
fun cancel_notRun() {
underTest.cancel()
- verifyZeroInteractions(runnable)
+ verifyNoMoreInteractions(runnable)
verify(consumer).accept(underTest)
- verifyZeroInteractions(workspace)
+ verifyNoMoreInteractions(workspace)
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index 909aabd..6313cf0 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -47,7 +47,7 @@
+ ")$");
private static final Pattern PLATFORM_BUILD =
Pattern.compile("^("
- + "(?<commandLine>eng\\.[a-z]+\\.[0-9]+\\.[0-9]+)|"
+ + "(?<commandLine>eng\\..+)|"
+ "(?<presubmit>P[0-9]+)|"
+ "(?<postsubmit>[0-9]+)"
+ ")$");
@@ -109,6 +109,9 @@
getPackageManager().
getPackageInfo(launcherPackageName, 0)
.versionName;
+ if (launcherVersion == null) {
+ return LOCAL;
+ }
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt
index 7b629bf..7a858e4 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt
@@ -85,7 +85,8 @@
Point(1, 1) to WidgetPreviewContainerSize(1, 1),
// 2x1
Point(2, 1) to WidgetPreviewContainerSize(2, 1),
- Point(3, 1) to WidgetPreviewContainerSize(2, 1),
+ // 3x1
+ Point(3, 1) to WidgetPreviewContainerSize(3, 1),
// 4x1
Point(4, 1) to WidgetPreviewContainerSize(4, 1),
// 2x2
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index 05a1224..c7c9dbb 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -25,7 +25,6 @@
import android.content.Intent;
import android.platform.test.annotations.PlatinumTest;
-import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.Launcher;
@@ -33,7 +32,6 @@
import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.Test;
@@ -191,7 +189,6 @@
/**
* Makes sure that when pressing back when AllApps is open we go back to the Home screen.
*/
- @FlakyTest(bugId = 256615483)
@Test
@PortraitLandscape
public void testPressBackFromAllAppsToHome() {
diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
index 4cecb5a..bcb9191 100644
--- a/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
+++ b/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
@@ -21,6 +21,7 @@
import android.view.View
import android.view.ViewGroup
import com.android.launcher3.CellLayout
+import com.android.launcher3.Utilities
import com.android.launcher3.Workspace
import com.android.launcher3.util.CellAndSpan
import com.android.launcher3.widget.LauncherAppWidgetHostView
@@ -54,7 +55,7 @@
return view as LauncherAppWidgetHostView
}
- fun getCellTopLeftRelativeToCellLayout(
+ fun getCellTopLeftRelativeToWorkspace(
workspace: Workspace<*>,
cellAndSpan: CellAndSpan
): Point {
@@ -67,6 +68,8 @@
cellAndSpan.spanY,
target
)
- return Point(target.left, target.top)
+ val point = floatArrayOf(target.left.toFloat(), target.top.toFloat())
+ Utilities.getDescendantCoordRelativeToAncestor(cellLayout, workspace, point, false)
+ return Point(point[0].toInt(), point[1].toInt())
}
}
diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
index 365ad4b..5e062d0 100644
--- a/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
+++ b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
@@ -35,9 +35,10 @@
companion object {
private const val TAG = "EventWaiter"
+ private val SIGNAL_TIMEOUT = TimeUnit.SECONDS.toMillis(5)
}
- fun waitForSignal(timeout: Long = TimeUnit.SECONDS.toMillis(10)) = runBlocking {
+ fun waitForSignal(timeout: Long = SIGNAL_TIMEOUT) = runBlocking {
var status = withTimeoutOrNull(timeout) { deferrable.await() }
if (status == null) {
status = EventStatus.TIMEOUT
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 907aa50..7c87c65 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -98,7 +98,6 @@
@Test
@PortraitLandscape
@PlatinumTest(focusArea = "launcher")
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/311099513
public void testUninstallFromWorkspace() throws Exception {
installDummyAppAndWaitForUIUpdate();
try {
diff --git a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt b/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
index d9af07a..05f626d 100644
--- a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
@@ -58,7 +58,8 @@
@RunWith(AndroidJUnit4::class)
class PackageUpdatedTaskTest {
- @get:Rule val setFlagsRule = SetFlagsRule()
+ @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+ @get:Rule(order = 1) val modelTestRule = ModelTestRule()
private val mUser = UserHandle(0)
private val mDataModel: BgDataModel = BgDataModel()
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
new file mode 100644
index 0000000..b93c305
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.PackageInstaller
+import android.content.pm.ShortcutInfo
+import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
+import android.util.LongSparseArray
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+import com.android.launcher3.Utilities
+import com.android.launcher3.model.data.IconRequestInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.PackageManagerHelper
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.util.UserIconInfo
+import com.android.launcher3.widget.WidgetInflater
+import com.android.launcher3.widget.WidgetSections
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.RETURNS_DEEP_STUBS
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
+
+@RunWith(AndroidJUnit4::class)
+class WorkspaceItemProcessorExtraTest {
+
+ @Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
+ @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
+ @Mock private lateinit var mockBgDataModel: BgDataModel
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var mockAppState: LauncherAppState
+ @Mock private lateinit var mockPmHelper: PackageManagerHelper
+ @Mock private lateinit var mockLauncherApps: LauncherApps
+ @Mock private lateinit var mockCursor: LoaderCursor
+ @Mock private lateinit var mockUserCache: UserCache
+ @Mock private lateinit var mockUserManagerState: UserManagerState
+ @Mock private lateinit var mockWidgetInflater: WidgetInflater
+
+ private var intent: Intent = Intent()
+ private var mUserHandle: UserHandle = UserHandle(0)
+ private var mIconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf()
+ private var mComponentName: ComponentName = ComponentName("package", "class")
+ private var mUnlockedUsersArray: LongSparseArray<Boolean> = LongSparseArray()
+ private var mKeyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo> = mutableMapOf()
+ private var mInstallingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf()
+ private var mAllDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
+ private var mWidgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> =
+ mutableMapOf()
+ private var mPendingPackages: MutableSet<PackageUserKey> = mutableSetOf()
+
+ private lateinit var itemProcessorUnderTest: WorkspaceItemProcessor
+
+ @Before
+ fun setup() {
+ mUserHandle = UserHandle(0)
+ mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
+ mockWorkspaceInfo = mock<WorkspaceItemInfo>()
+ mockBgDataModel = mock<BgDataModel>()
+ mComponentName = ComponentName("package", "class")
+ mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
+ intent =
+ Intent().apply {
+ component = mComponentName
+ `package` = "pkg"
+ putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
+ }
+ mockContext =
+ mock<Context>().apply {
+ whenever(packageManager).thenReturn(mock())
+ whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
+ whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
+ }
+ mockAppState =
+ mock<LauncherAppState>().apply {
+ whenever(context).thenReturn(mockContext)
+ whenever(iconCache).thenReturn(mock())
+ whenever(iconCache.getShortcutIcon(any(), any(), any())).then {}
+ }
+ mockPmHelper =
+ mock<PackageManagerHelper>().apply {
+ whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+ .thenReturn(intent)
+ }
+ mockLauncherApps =
+ mock<LauncherApps>().apply {
+ whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+ whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
+ }
+ mockCursor =
+ Mockito.mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
+ user = mUserHandle
+ itemType = ITEM_TYPE_APPLICATION
+ id = 1
+ restoreFlag = 1
+ serialNumber = 101
+ whenever(parseIntent()).thenReturn(intent)
+ whenever(markRestored()).doAnswer { restoreFlag = 0 }
+ whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
+ whenever(getAppShortcutInfo(any(), any(), any(), any()))
+ .thenReturn(mockWorkspaceInfo)
+ whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
+ }
+ mockUserCache =
+ mock<UserCache>().apply {
+ val userIconInfo =
+ mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
+ whenever(getUserInfo(any())).thenReturn(userIconInfo)
+ }
+
+ mockUserManagerState = mock<UserManagerState>()
+ mockWidgetInflater = mock<WidgetInflater>()
+ mKeyToPinnedShortcutsMap = mutableMapOf()
+ mInstallingPkgs = hashMapOf()
+ mAllDeepShortcuts = mutableListOf()
+ mWidgetProvidersMap = mutableMapOf()
+ mIconRequestInfos = mutableListOf()
+ mPendingPackages = mutableSetOf()
+ }
+
+ @Test
+ fun `When Pending App Widget has not started restore then update db and add item`() {
+
+ val mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .mockStatic(WidgetSections::class.java)
+ .startMocking()
+ try {
+ // Given
+ val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+ val expectedComponentName =
+ ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
+ val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
+ val expectedAppWidgetId = 0
+ mockCursor.apply {
+ itemType = ITEM_TYPE_APPWIDGET
+ user = mUserHandle
+ restoreFlag = FLAG_UI_NOT_READY
+ container = CONTAINER_DESKTOP
+ whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+ whenever(appWidgetProvider).thenReturn(expectedProvider)
+ whenever(appWidgetId).thenReturn(expectedAppWidgetId)
+ whenever(spanX).thenReturn(2)
+ whenever(spanY).thenReturn(1)
+ whenever(options).thenReturn(0)
+ whenever(appWidgetSource).thenReturn(20)
+ whenever(applyCommonProperties(any())).thenCallRealMethod()
+ whenever(
+ updater()
+ .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
+ .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+ .put(Favorites.RESTORED, expectedRestoreStatus)
+ .commit()
+ )
+ .thenReturn(1)
+ }
+ val inflationResult =
+ WidgetInflater.InflationResult(
+ type = WidgetInflater.TYPE_PENDING,
+ widgetInfo = null
+ )
+ mockWidgetInflater =
+ mock<WidgetInflater>().apply {
+ whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+ }
+ val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
+ mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
+
+ // When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ val expectedWidgetInfo =
+ LauncherAppWidgetInfo().apply {
+ appWidgetId = expectedAppWidgetId
+ providerName = ComponentName.unflattenFromString(expectedProvider)
+ restoreStatus = expectedRestoreStatus
+ }
+ verify(
+ mockCursor
+ .updater()
+ .put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
+ .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+ .put(Favorites.RESTORED, expectedRestoreStatus)
+ )
+ .commit()
+ val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
+ verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
+ val actualWidgetInfo = widgetInfoCaptor.value
+ with(actualWidgetInfo) {
+ assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
+ assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
+ assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
+ assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
+ }
+ } finally {
+ mockitoSession.finishMocking()
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+ fun `When Archived Pending App Widget then checkAndAddItem`() {
+ val mockitoSession =
+ ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
+ try {
+ // Given
+ val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+ val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
+ val expectedPackage = expectedComponentName!!.packageName
+ mockPmHelper =
+ mock<PackageManagerHelper>().apply {
+ whenever(isAppArchived(expectedPackage)).thenReturn(true)
+ }
+ mockCursor =
+ mock<LoaderCursor>().apply {
+ itemType = ITEM_TYPE_APPWIDGET
+ id = 1
+ user = UserHandle(1)
+ restoreFlag = FLAG_UI_NOT_READY
+ container = CONTAINER_DESKTOP
+ whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+ whenever(appWidgetProvider).thenReturn(expectedProvider)
+ whenever(appWidgetId).thenReturn(0)
+ whenever(spanX).thenReturn(2)
+ whenever(spanY).thenReturn(1)
+ whenever(options).thenReturn(0)
+ whenever(appWidgetSource).thenReturn(20)
+ whenever(applyCommonProperties(any())).thenCallRealMethod()
+ }
+ mInstallingPkgs = hashMapOf()
+ val inflationResult =
+ WidgetInflater.InflationResult(
+ type = WidgetInflater.TYPE_PENDING,
+ widgetInfo = null
+ )
+ mockWidgetInflater =
+ mock<WidgetInflater>().apply {
+ whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+ }
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockCursor).checkAndAddItem(any(), any())
+ } finally {
+ mockitoSession.finishMocking()
+ }
+ }
+
+ private fun createWorkspaceItemProcessorUnderTest(
+ cursor: LoaderCursor = mockCursor,
+ memoryLogger: LoaderMemoryLogger? = null,
+ userCache: UserCache = mockUserCache,
+ userManagerState: UserManagerState = mockUserManagerState,
+ launcherApps: LauncherApps = mockLauncherApps,
+ shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap,
+ app: LauncherAppState = mockAppState,
+ bgDataModel: BgDataModel = mockBgDataModel,
+ widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap,
+ widgetInflater: WidgetInflater = mockWidgetInflater,
+ pmHelper: PackageManagerHelper = mockPmHelper,
+ iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mIconRequestInfos,
+ isSdCardReady: Boolean = false,
+ pendingPackages: MutableSet<PackageUserKey> = mPendingPackages,
+ unlockedUsers: LongSparseArray<Boolean> = mUnlockedUsersArray,
+ installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = mInstallingPkgs,
+ allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts
+ ) =
+ WorkspaceItemProcessor(
+ c = cursor,
+ memoryLogger = memoryLogger,
+ userCache = userCache,
+ userManagerState = userManagerState,
+ launcherApps = launcherApps,
+ app = app,
+ bgDataModel = bgDataModel,
+ widgetProvidersMap = widgetProvidersMap,
+ widgetInflater = widgetInflater,
+ pmHelper = pmHelper,
+ unlockedUsers = unlockedUsers,
+ iconRequestInfos = iconRequestInfos,
+ pendingPackages = pendingPackages,
+ isSdCardReady = isSdCardReady,
+ shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
+ installingPkgs = installingPkgs,
+ allDeepShortcuts = allDeepShortcuts
+ )
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
similarity index 100%
rename from tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
rename to tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 749a75a..68004bb 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -351,8 +351,6 @@
/** Waits for setup wizard to go away. */
private static void waitForSetupWizardDismissal() {
- if (!TestStabilityRule.isPresubmit()) return;
-
if (sFirstTimeWaitingForWizard) {
try {
getUiDevice().executeShellCommand(
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/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 9b184ae..9c916fa 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.ui.widget;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
import static org.junit.Assert.assertNotNull;
import android.platform.test.annotations.PlatinumTest;
@@ -33,7 +30,6 @@
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import org.junit.Assume;
@@ -102,7 +98,6 @@
/**
* Test dragging a widget to the workspace and resize it.
*/
- @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/316910614
@PlatinumTest(focusArea = "launcher")
@Test
public void testResizeWidget() throws Throwable {
diff --git a/tests/src/com/android/launcher3/util/RoboApiWrapper.kt b/tests/src/com/android/launcher3/util/RoboApiWrapper.kt
new file mode 100644
index 0000000..583652d
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/RoboApiWrapper.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.content.ContentResolver
+import android.net.Uri
+import android.os.Looper
+import java.io.InputStream
+import java.util.function.Supplier
+
+object RoboApiWrapper {
+
+ fun initialize() {}
+
+ fun registerInputStream(
+ contentResolver: ContentResolver,
+ uri: Uri,
+ inputStreamSupplier: Supplier<InputStream>
+ ) {}
+
+ fun waitForLooperSync(looper: Looper) {}
+}
diff --git a/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt b/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt
new file mode 100644
index 0000000..9232268
--- /dev/null
+++ b/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.content.ComponentName
+import android.content.ContentResolver
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
+import android.content.pm.LauncherActivityInfo
+import android.content.pm.LauncherApps
+import android.net.Uri
+import android.os.Looper
+import android.os.Process
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.InputStream
+import java.util.function.Supplier
+import org.mockito.Mockito
+import org.mockito.kotlin.whenever
+import org.robolectric.RuntimeEnvironment
+import org.robolectric.Shadows
+
+object RoboApiWrapper {
+
+ fun initialize() {
+ Shadows.shadowOf(
+ RuntimeEnvironment.getApplication().getSystemService(LauncherApps::class.java)
+ )
+ .addEnabledPackage(
+ Process.myUserHandle(),
+ InstrumentationRegistry.getInstrumentation().context.packageName
+ )
+ LauncherModelHelper.ACTIVITY_LIST.forEach {
+ installApp(ComponentName(InstrumentationRegistry.getInstrumentation().context, it))
+ }
+ }
+
+ private fun installApp(componentName: ComponentName) {
+ val app = RuntimeEnvironment.getApplication()
+ val user = Process.myUserHandle()
+
+ val pm = Shadows.shadowOf(app.packageManager)
+ val ai = pm.addActivityIfNotPresent(componentName)
+ pm.addIntentFilterForActivity(
+ componentName,
+ IntentFilter(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
+ )
+
+ val li = Mockito.mock(LauncherActivityInfo::class.java)
+ val appInfo = ApplicationInfo().apply { flags = 0 }
+ Mockito.doReturn(ai).whenever(li).activityInfo
+ Mockito.doReturn(appInfo).whenever(li).applicationInfo
+ Mockito.doReturn(user).whenever(li).user
+ Mockito.doReturn(1f).whenever(li).loadingProgress
+ Mockito.doReturn(componentName).whenever(li).componentName
+
+ Shadows.shadowOf(app.getSystemService(LauncherApps::class.java)).apply {
+ addActivity(user, li)
+ addEnabledPackage(user, componentName.packageName)
+ setActivityEnabled(user, componentName)
+ addApplicationInfo(user, componentName.packageName, ai.applicationInfo)
+ }
+ }
+
+ fun registerInputStream(
+ contentResolver: ContentResolver,
+ uri: Uri,
+ inputStreamSupplier: Supplier<InputStream>
+ ) {
+ Shadows.shadowOf(contentResolver).registerInputStreamSupplier(uri, inputStreamSupplier)
+ }
+
+ fun waitForLooperSync(looper: Looper) {
+ Shadows.shadowOf(looper).runToEndOfTasks()
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 7c6d684..02a862d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
+import android.graphics.Point;
import android.util.Log;
import android.widget.TextView;
@@ -129,6 +130,14 @@
}
/**
+ * @return the center coordinates of the icon
+ */
+ @NonNull
+ public Point getVisibleCenter() {
+ return getObject().getVisibleCenter();
+ }
+
+ /**
* Create a regular expression pattern that matches strings containing all of the non-whitespace
* characters of the app name, with any amount of whitespace added between characters (e.g.
* newline for multiline app labels).
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index e71b49f..0edcfea 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -23,9 +23,9 @@
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 static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.graphics.Rect;
-import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
@@ -278,7 +278,7 @@
if (mLauncher.isTablet()) {
mLauncher.assertTrue("current task is not grid height",
getCurrentTask().getVisibleHeight() == mLauncher
- .getGridTaskRectForTablet().height());
+ .getOverviewGridTaskSize().height());
}
mLauncher.assertTrue("Current task not scrolled off screen",
!getCurrentTask().equals(task));
@@ -354,7 +354,7 @@
final List<UiObject2> taskViews = getTasks();
mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
- final int gridTaskWidth = mLauncher.getGridTaskRectForTablet().width();
+ final int gridTaskWidth = mLauncher.getOverviewGridTaskSize().width();
return taskViews.stream().filter(t -> t.getVisibleBounds().width() == gridTaskWidth).map(
t -> new OverviewTask(mLauncher, t, this)).collect(Collectors.toList());
@@ -422,31 +422,32 @@
protected boolean isActionsViewVisible() {
if (!hasTasks() || isClearAllVisible()) {
- Log.d(TAG, "Not expecting an actions bar: no tasks/'Clear all' is visible");
+ testLogD(TAG, "Not expecting an actions bar: no tasks/'Clear all' is visible");
return false;
}
boolean isTablet = mLauncher.isTablet();
if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) {
- Log.d(TAG, "Not expecting an actions bar: device is tablet with grid-only Overview");
+ testLogD(TAG, "Not expecting an actions bar: device is tablet with grid-only Overview");
return false;
}
OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
if (task == null) {
- Log.d(TAG, "Not expecting an actions bar: no current task");
+ testLogD(TAG, "Not expecting an actions bar: no current task");
return false;
}
// In tablets, if focused task is not in center, overview actions aren't visible.
if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
- Log.d(TAG, "Not expecting an actions bar: device is tablet and task is not centered");
+ testLogD(TAG,
+ "Not expecting an actions bar: device is tablet and task is not centered");
return false;
}
if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
- Log.d(TAG, "Not expecting an actions bar: device is phone and task is split");
+ testLogD(TAG, "Not expecting an actions bar: device is phone and task is split");
// Overview actions aren't visible for split screen tasks, except for save app pair
// button on tablets.
return false;
}
- Log.d(TAG, "Expecting an actions bar");
+ testLogD(TAG, "Expecting an actions bar");
return true;
}
@@ -529,13 +530,13 @@
throw new IllegalStateException("Must be run on tablet device.");
}
final List<UiObject2> taskViews = getTasks();
- if (taskViews.size() == 0) {
+ if (taskViews.isEmpty()) {
return null;
}
- int focusedTaskHeight = mLauncher.getFocusedTaskHeightForTablet();
+ Rect focusTaskSize = mLauncher.getOverviewTaskSize();
+ int focusedTaskHeight = focusTaskSize.height();
for (UiObject2 task : taskViews) {
OverviewTask overviewTask = new OverviewTask(mLauncher, task, this);
-
if (overviewTask.getVisibleHeight() == focusedTaskHeight) {
return overviewTask;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index a874062..d3c423e 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -428,14 +428,14 @@
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- int getFocusedTaskHeightForTablet() {
- return getTestInfo(TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET).getInt(
- TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ Rect getOverviewTaskSize() {
+ return getTestInfo(TestProtocol.REQUEST_GET_OVERVIEW_TASK_SIZE)
+ .getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, Rect.class);
}
- Rect getGridTaskRectForTablet() {
- return ((Rect) getTestInfo(TestProtocol.REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET)
- .getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD));
+ Rect getOverviewGridTaskSize() {
+ return getTestInfo(TestProtocol.REQUEST_GET_OVERVIEW_GRID_TASK_SIZE)
+ .getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, Rect.class);
}
int getOverviewPageSpacing() {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 7a8ab49..5433fa7 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -156,8 +156,8 @@
return;
}
- boolean taskWasFocused = mLauncher.isTablet() && getVisibleHeight() == mLauncher
- .getFocusedTaskHeightForTablet();
+ boolean taskWasFocused = mLauncher.isTablet()
+ && getVisibleHeight() == mLauncher.getOverviewTaskSize().height();
List<Integer> originalTasksCenterX =
getCurrentTasksCenterXList().stream().sorted().toList();
boolean isClearAllVisibleBeforeDismiss = mOverview.isClearAllVisible();
@@ -284,8 +284,9 @@
*
* TODO(b/326565120): remove Nullable support once the bug causing it to be null is fixed.
*/
- public boolean containsContentDescription(@Nullable String expected) {
- String actual = mTask.getContentDescription();
+ public boolean containsContentDescription(@Nullable String expected,
+ OverviewSplitTask overviewSplitTask) {
+ String actual = findObjectInTask(overviewSplitTask.snapshotRes).getContentDescription();
if (actual == null && expected == null) {
return true;
}
@@ -295,6 +296,14 @@
return actual.contains(expected);
}
+ /**
+ * Returns whether the given String is contained in this Task's contentDescription. Also returns
+ * true if both Strings are null
+ */
+ public boolean containsContentDescription(@Nullable String expected) {
+ return containsContentDescription(expected, DEFAULT);
+ }
+
private TaskViewType getType() {
String resourceName = mTask.getResourceName();
if (resourceName.endsWith("task_view_grouped")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index e6315f3..b4aaab7 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -52,7 +52,7 @@
if (!mLauncher.isTransientTaskbar()) {
Assert.assertEquals("Persistent taskbar should fill screen width",
- getVisibleBounds().width(), mLauncher.getRealDisplaySize().x);
+ mLauncher.getRealDisplaySize().x, getVisibleBounds().width());
}
}