Merge "Tune the window to icon and home scaling animation." into main
diff --git a/OWNERS b/OWNERS
index 654493f..e715b8b 100644
--- a/OWNERS
+++ b/OWNERS
@@ -28,6 +28,7 @@
tracyzhou@google.com
peanutbutter@google.com
jeremysim@google.com
+atsjenk@google.com
# Overview eng team
alexchau@google.com
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 6b07bb6..dd78ca4 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -231,6 +231,13 @@
}
flag {
+ name: "enable_refactor_task_thumbnail"
+ namespace: "launcher"
+ description: "Enables rewritten version of TaskThumbnailViews in Overview"
+ bug: "331753115"
+}
+
+flag {
name: "enable_handle_delayed_gesture_callbacks"
namespace: "launcher"
description: "Enables additional handling for delayed mid-gesture callbacks"
@@ -239,3 +246,34 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_fallback_overview_in_window"
+ namespace: "launcher"
+ description: "Enables fallback recents opening inside of a window instead of an activity."
+ bug: "292269949"
+}
+
+flag {
+ name: "enable_smartspace_as_a_widget"
+ namespace: "launcher"
+ description: "Enables smartspace as a widget"
+ bug: "300140279"
+}
+
+flag {
+ name: "enable_smartspace_removal_toggle"
+ namespace: "launcher"
+ description: "Enables smartspace removal toggle"
+ bug: "303471576"
+}
+
+flag {
+ name: "enable_additional_home_animations"
+ namespace: "launcher"
+ description: "Enables custom home animations for non-running tasks"
+ bug: "237638627"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index df09124..b1a6202 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -121,6 +121,17 @@
android:layout_weight="1"
android:visibility="gone" />
+ </LinearLayout>
+
+ <!-- Unused. Included only for compatibility with parent class. -->
+ <LinearLayout
+ android:id="@+id/group_action_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/overview_actions_height"
+ android:layout_gravity="top|center_horizontal"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
<Button
android:id="@+id/action_save_app_pair"
style="@style/GoOverviewActionButton"
@@ -128,8 +139,8 @@
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_save_app_pair_up_down"
android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor"
- android:visibility="gone" />
+ android:theme="@style/ThemeControlHighlightWorkspaceColor" />
+
</LinearLayout>
</com.android.quickstep.views.GoOverviewActionsView>
\ No newline at end of file
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
index 0d0f700..556d29c 100644
--- a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
@@ -35,6 +35,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.launcher3.model.AppShareabilityDatabase.ShareabilityDao;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
import java.lang.annotation.Retention;
import java.util.ArrayList;
@@ -47,7 +48,7 @@
* Each app's status is retrieved from the Play Store's API. Statuses are cached in order
* to limit extraneous calls to that API (which can be time-consuming).
*/
-public class AppShareabilityManager {
+public class AppShareabilityManager implements SafeCloseable {
@Retention(SOURCE)
@IntDef({
ShareabilityStatus.UNKNOWN,
@@ -194,6 +195,11 @@
}
}
+ @Override
+ public void close() {
+ mDatabase.close();
+ }
+
/**
* Provides a testable instance of this class
* This instance allows database queries on the main thread
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 253147d..0eb8775 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -56,7 +56,7 @@
import com.android.quickstep.util.AssistContentRequester;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.views.GoOverviewActionsView;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -101,7 +101,7 @@
/**
* Create a new overlay instance for the given View
*/
- public TaskOverlayGo createOverlay(TaskThumbnailView thumbnailView) {
+ public TaskOverlayGo createOverlay(TaskThumbnailViewDeprecated thumbnailView) {
return new TaskOverlayGo(thumbnailView, mContentRequester);
}
@@ -120,7 +120,7 @@
private OverlayDialogGo mDialog;
private ArrowTipView mArrowTipView;
- private TaskOverlayGo(TaskThumbnailView taskThumbnailView,
+ private TaskOverlayGo(TaskThumbnailViewDeprecated taskThumbnailView,
AssistContentRequester assistContentRequester) {
super(taskThumbnailView);
mFactoryContentRequester = assistContentRequester;
diff --git a/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml
new file mode 100644
index 0000000..d722dd7
--- /dev/null
+++ b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml
@@ -0,0 +1,27 @@
+<?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.
+ -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:inset="@dimen/bubble_expanded_view_drop_target_padding">
+ <shape
+ android:shape="rectangle">
+ <corners android:radius="@dimen/bubble_expanded_view_drop_target_corner_radius" />
+ <solid android:color="@color/bubblebar_drop_target_bg_color" />
+ <stroke
+ android:width="1dp"
+ android:color="?androidprv:attr/materialColorPrimaryContainer" />
+ </shape>
+</inset>
diff --git a/quickstep/res/layout/bubble_expanded_view_drop_target.xml b/quickstep/res/layout/bubble_expanded_view_drop_target.xml
new file mode 100644
index 0000000..3bd5d31
--- /dev/null
+++ b/quickstep/res/layout/bubble_expanded_view_drop_target.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.
+ -->
+
+<!-- TODO(b/330585402): replace 600dp height with calculated value -->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/bubble_expanded_view_drop_target_default_width"
+ android:layout_height="@dimen/bubble_expanded_view_drop_target_default_height"
+ android:layout_margin="@dimen/bubble_expanded_view_drop_target_margin"
+ android:background="@drawable/bg_bubble_expanded_view_drop_target"
+ android:elevation="@dimen/bubblebar_elevation" />
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index d086da4..7aaf744 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -45,14 +45,24 @@
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/group_action_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/overview_actions_height"
+ android:layout_gravity="bottom|center_horizontal"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
<Button
android:id="@+id/action_save_app_pair"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor"
- android:visibility="gone" />
+ android:theme="@style/ThemeControlHighlightWorkspaceColor" />
+
</LinearLayout>
</com.android.quickstep.views.OverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index a1bcad0..b004dfd 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -134,11 +134,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
+ android:layout_above="@id/gesture_tutorial_fragment_action_button"
android:layout_centerHorizontal="true"
android:background="@android:color/transparent"
- android:paddingEnd="24dp"
- android:paddingStart="24dp"
- android:paddingTop="24dp">
+ android:paddingTop="24dp"
+ android:paddingHorizontal="24dp"
+ android:layout_marginBottom="16dp">
<TextView
android:id="@+id/gesture_tutorial_fragment_feedback_title"
@@ -169,7 +170,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="@id/gesture_tutorial_fragment_action_button"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -193,7 +194,7 @@
android:id="@+id/checkmark_animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="44dp"
+ android:layout_marginBottom="28dp"
android:gravity="center"
android:scaleType="centerCrop"
app:lottie_loop="false"
@@ -204,19 +205,6 @@
app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_subtitle"
app:layout_constraintBottom_toBottomOf="parent" />
- <Button
- android:id="@+id/gesture_tutorial_fragment_action_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/gesture_tutorial_action_button_background"
- android:stateListAnimator="@null"
- android:text="@string/gesture_tutorial_action_button_label"
- android:visibility="invisible"
- android:layout_marginBottom="60dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/checkmark_animation" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -228,4 +216,18 @@
android:src="@drawable/gesture_tutorial_finger_dot"
android:visibility="gone" />
+ <Button
+ android:id="@+id/gesture_tutorial_fragment_action_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/gesture_tutorial_done_button_end_margin"
+ android:layout_marginBottom="@dimen/gesture_tutorial_done_button_bottom_margin"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:background="@drawable/gesture_tutorial_action_button_background"
+ android:stateListAnimator="@null"
+ android:text="@string/gesture_tutorial_action_button_label"
+ android:visibility="invisible"
+ />
+
</com.android.quickstep.interaction.RootSandboxLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 9d599c9..cc3b30e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,10 +28,7 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <com.android.quickstep.views.TaskThumbnailView
- android:id="@+id/snapshot"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ <include layout="@layout/task_thumbnail" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 3cafcfd..89e9b3d 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -42,10 +42,7 @@
views that do not inherint from TaskView only or create a generic TaskView that have
N number of tasks.
-->
- <com.android.quickstep.views.TaskThumbnailView
- android:id="@+id/snapshot"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ <include layout="@layout/task_thumbnail"
android:visibility="gone" />
<ViewStub
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index e91e773..87a0f70 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,15 +33,10 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <com.android.quickstep.views.TaskThumbnailView
- android:id="@+id/snapshot"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ <include layout="@layout/task_thumbnail"/>
- <com.android.quickstep.views.TaskThumbnailView
- android:id="@+id/bottomright_snapshot"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ <include layout="@layout/task_thumbnail"
+ android:id="@+id/bottomright_snapshot" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_menu_with_arrow.xml b/quickstep/res/layout/task_menu_with_arrow.xml
index c9108a5..88e5cf7 100644
--- a/quickstep/res/layout/task_menu_with_arrow.xml
+++ b/quickstep/res/layout/task_menu_with_arrow.xml
@@ -18,6 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minWidth="@dimen/task_menu_width_grid"
android:animateLayoutChanges="true"
android:background="@drawable/task_menu_bg"
android:orientation="vertical"
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
new file mode 100644
index 0000000..f1a3d62
--- /dev/null
+++ b/quickstep/res/layout/task_thumbnail.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.quickstep.views.TaskThumbnailViewDeprecated
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/snapshot"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_edu_circle_to_search.xml b/quickstep/res/layout/taskbar_edu_search.xml
similarity index 79%
rename from quickstep/res/layout/taskbar_edu_circle_to_search.xml
rename to quickstep/res/layout/taskbar_edu_search.xml
index 6c95f25..ca84f35 100644
--- a/quickstep/res/layout/taskbar_edu_circle_to_search.xml
+++ b/quickstep/res/layout/taskbar_edu_search.xml
@@ -23,35 +23,35 @@
style="@style/TextAppearance.TaskbarEduTooltip.Title"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:text="@string/taskbar_edu_circle_to_search_title"
+ android:text="@string/taskbar_search_edu_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/circle_to_search_animation" />
+ app:layout_constraintBottom_toTopOf="@+id/search_edu_animation" />
<com.airbnb.lottie.LottieAnimationView
- android:id="@+id/circle_to_search_animation"
+ android:id="@+id/search_edu_animation"
android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
android:layout_height="@dimen/taskbar_edu_swipe_lottie_height"
android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
- app:layout_constraintBottom_toTopOf="@id/circle_to_search_text"
+ app:layout_constraintBottom_toTopOf="@id/search_edu_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
- app:lottie_rawRes="@raw/taskbar_edu_circle_to_search"
+ app:lottie_rawRes="@raw/taskbar_edu_search"
app:lottie_autoPlay="true"
app:lottie_loop="true" />
<TextView
- android:id="@+id/circle_to_search_text"
+ android:id="@+id/search_edu_text"
style="@style/TextAppearance.TaskbarEduTooltip.Subtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
- android:textSize="@dimen/taskbar_edu_circle_to_search_subtitle_text_size"
+ android:textSize="@dimen/taskbar_edu_search_subtitle_text_size"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/circle_to_search_animation"
+ app:layout_constraintTop_toBottomOf="@id/search_edu_animation"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
index 3c6878a..7c55bf8 100644
--- a/quickstep/res/layout/transient_taskbar.xml
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -44,7 +44,7 @@
android:layout_height="@dimen/bubblebar_size_with_pointer"
android:layout_gravity="bottom|end"
android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
- android:paddingTop="@dimen/bubblebar_pointer_size"
+ android:paddingTop="@dimen/bubblebar_pointer_visible_size"
android:paddingEnd="@dimen/taskbar_icon_spacing"
android:paddingStart="@dimen/taskbar_icon_spacing"
android:visibility="gone"
diff --git a/quickstep/res/raw/taskbar_edu_circle_to_search.json b/quickstep/res/raw/taskbar_edu_search.json
similarity index 100%
rename from quickstep/res/raw/taskbar_edu_circle_to_search.json
rename to quickstep/res/raw/taskbar_edu_search.json
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 6a749d1..39cca0c 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Doen meer met die Taakbalk"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Wys altyd die Taakbalk"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Raak en hou die verdeler in om altyd die Taakbalk onderaan jou skerm te wys"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Raak en hou die aksiesleutel om te soek wat op jou skerm is"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Hierdie produk gebruik die deel van jou skerm wat gekies is om te soek. Google se <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privaatheidsbeleid<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> en <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>diensbepalings<xliff:g id="END_TOS_LINK"></a></xliff:g> geld."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Raak en hou die handelingsleutel om te soek wat op jou skerm is"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Hierdie produk gebruik die gekose deel van jou skerm om te soek. Google se <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privaatheidsbeleid<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> en <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>diensbepalings<xliff:g id="END_TOS_LINK"></a></xliff:g> geld."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Maak toe"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Tuis"</string>
@@ -138,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Voeg nou app by werkskerm"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Kanselleer"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 959d06c..948a86d 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ዴስክቶፕ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"በተግባር አሞሌው ተጨማሪ ነገር ያድርጉ"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"የተግባር አሞሌውን ሁልጊዜ አሳይ"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"በማያ ገጽዎ ግርጌ ላይ ያለውን የተግባር አሞሌ ሁልጊዜ ለማሳየት፣ መክፈያን ይንኩ እና ይያዙ"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"በማያ ገጽዎ ላይ ያለውን ነገር ለመፈለግ የተግባር ቁልፉን ነክተው ይያዙ"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ይህ ምርት የተመረጠውን የማያ ገጽዎን ክፍል ለመፈለግ ይጠቀማል። የGoogle <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>የግላዊነት መመሪያ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> እና <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>የአገልግሎት ውል<xliff:g id="END_TOS_LINK"></a></xliff:g> ተፈጻሚ ናቸው።"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"በማያ ገጽዎ ላይ ያለውን ነገር ለመፈለግ የተግባር ቁልፉን ነክተው ይያዙ"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ይህ ምርት የተመረጠውን የማያ ገጽዎን ክፍል ለመፈለግ ይጠቀማል። የGoogle <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>የግላዊነት መመሪያ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> እና <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>የአገልግሎት ውል<xliff:g id="END_TOS_LINK"></a></xliff:g> ተፈጻሚ ናቸው።"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ተጠናቅቋል"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"መነሻ"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"መተግበሪያን ወደ ዴስክቶፕ በማከል ላይ"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ይቅር"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 2eaea0c..31f8922 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"شكل مجاني"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"الكمبيوتر المكتبي"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ما مِن عناصر تم استخدامها مؤخرًا"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"إعدادات استخدام التطبيق"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"محو الكل"</string>
@@ -89,9 +88,9 @@
<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="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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"إنجاز المزيد باستخدام شريط التطبيقات"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"عرض \"شريط التطبيقات\" دائمًا"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"انقر مع الاستمرار على أداة تقسيم الشاشة لعرض \"شريط التطبيقات\" دائمًا في أسفل الشاشة."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"انقر مع الاستمرار على مفتاح الإجراء للبحث عن المحتوى الذي يظهر على شاشتك"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"يستخدم هذا المنتج الجزء المحدّد من الشاشة للبحث. تسري <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>سياسة خصوصية<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> Google و<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>بنود خدمتها<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"انقر مع الاستمرار على مفتاح الإجراء للبحث عن المحتوى الذي يظهر على شاشتك"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"يستخدم هذا المنتج الجزء المحدّد من الشاشة للبحث. تسري <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>سياسة الخصوصية<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> و<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>بنود الخدمة<xliff:g id="END_TOS_LINK"></a></xliff:g> في Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"إغلاق"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"تم"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"الرئيسية"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"إضافة تطبيق إلى سطح المكتب"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"إلغاء"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index c483fb1..009993d 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"টাস্কবাৰৰ জৰিয়তে অধিক কাৰ্য সম্পাদন কৰক"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"টাস্কবাৰডাল সদায় দেখুৱাওক"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"আপোনাৰ স্ক্ৰীনৰ তলত সদায় টাস্কবাৰডাল দেখুৱাবলৈ বিভাজকডাল স্পৰ্শ কৰি ধৰি ৰাখক"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"আপোনাৰ স্ক্ৰীনখনত থকা সমল সন্ধান কৰিবলৈ কাৰ্য কীটো স্পৰ্শ কৰি ধৰি ৰাখক"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"এই প্ৰ’ডাক্টটোৱে সন্ধান কৰিবলৈ আপোনাৰ স্ক্ৰীনখনৰ বাছনি কৰা অংশ ব্যৱহাৰ কৰে। Googleৰ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>গোপনীয়তাৰ নীতি<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> আৰু <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>সেৱাৰ চৰ্তাৱলী<xliff:g id="END_TOS_LINK"></a></xliff:g> প্ৰযোজ্য।"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"আপোনাৰ স্ক্ৰীনখনত থকা সমল সন্ধান কৰিবলৈ কাৰ্য কীটো স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"এই প্ৰ’ডাক্টটোৱে সন্ধান কৰিবলৈ আপোনাৰ স্ক্ৰীনখনৰ বাছনি কৰা অংশ ব্যৱহাৰ কৰে। Googleৰ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>গোপনীয়তাৰ নীতি<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> আৰু <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>সেৱাৰ চৰ্তাৱলী<xliff:g id="END_TOS_LINK"></a></xliff:g> প্ৰযোজ্য।"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ কৰক"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"হ’ল"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"গৃহপৃষ্ঠা"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ডেস্কটপত এপ্ যোগ দি থকা হৈছে"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"বাতিল কৰক"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 1500e82..b30bf46 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Tapşırıq paneli ilə daha çox şey edin"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"İşləmə panelini həmişə göstərin"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"İşləmə panelini həmişə ekranın aşağısında göstərmək üçün ayırıcı üzərinə toxunun və saxlayın"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekranda axtarış etmək üçün fəaliyyət açarına toxunub saxlayın"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bu məhsul axtarış üçün ekranın seçilmiş hissəsindən istifadə edir. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Məxfilik Siyasəti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> və <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Xidmət Şərtləri<xliff:g id="END_TOS_LINK"></a></xliff:g> tətbiq edilir."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekranda axtarış etmək üçün fəaliyyət açarına toxunub saxlayın"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bu məhsul axtarış üçün ekranın seçilmiş hissəsindən istifadə edir. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Məxfilik Siyasəti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> və <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Xidmət Şərtləri<xliff:g id="END_TOS_LINK"></a></xliff:g> tətbiq edilir."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Bağlayın"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Hazırdır"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Ev"</string>
@@ -138,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Tətbiqin masaüstünə əlavə edilməsi"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Ləğv edin"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 9529776..9e437e7 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Uradite više pomoću trake zadataka"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Uvek prikazuj traku zadataka"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da bi traka zadataka uvek bila prikazana u dnu ekrana, dodirnite i zadržite razdelnik"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite taster radnji da biste pretražili ono što je na ekranu"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod koristi izabrani deo ekrana za pretragu. Primenjuju se Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>politika privatnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>uslovi korišćenja usluge<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Dodirnite i zadržite taster radnji da biste pretražili ono što je na ekranu"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ovaj proizvod koristi izabrani deo ekrana za pretragu. Primenjuju se Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>politika privatnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>uslovi korišćenja usluge<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodaje se aplikacija na radnu povrršinu"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Otkaži"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 6b20866..eed8863 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Адвольная форма"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Працоўны стол"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налады выкарыстання праграмы"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ачысціць усё"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Выкарыстоўвайце магчымасці панэлі задач"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Замацуйце панэль задач унізе экрана"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Для гэтага націсніце на раздзяляльнік і ўтрымлівайце яго"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Каб выканаць пошук па тым, што адлюстравана на экране, націсніце і ўтрымлівайце клавішу дзеяння"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Гэты прадукт выконвае пошук па змесціве выбранай часткі экрана. Дзейнічаюць <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Умовы выкарыстання<xliff:g id="END_TOS_LINK"></a></xliff:g> і <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Палітыка прыватнасці<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Для пошуку па змесціве экрана націсніце і ўтрымлівайце клавішу дзеяння"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Гэты прадукт выконвае пошук па змесціве выбранай часткі экрана. Прымяняюцца <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Умовы выкарыстання<xliff:g id="END_TOS_LINK"></a></xliff:g> і <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Палітыка прыватнасці<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Закрыць"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Гатова"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Галоўны экран"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Дадаванне праграмы на камп\'ютар"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Скасаваць"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 8631d8b..3c66e25 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Фиксиране"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Свободна форма"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"За компютър"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма скорошни елементи"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки за използването на приложенията"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Изчистване на всички"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повече неща с лентата на задачите"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Лентата на задачите да се показва винаги"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"За да фиксирате лентата на задачите най-долу на екрана, докоснете и задръжте разделителя"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Докоснете и задръжте клавиша за действия, за да извършите търсене със съдържанието на екрана"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Този продукт използва избраната част на екрана ви, за да търси. Прилагат се <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Декларацията за поверителност<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Общите условия<xliff:g id="END_TOS_LINK"></a></xliff:g> на Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Докоснете и задръжте клавиша за действия, за да извършите търсене със съдържанието на екрана"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Този продукт използва избраната част на екрана ви, за да търси. Прилагат се <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Декларацията за поверителност<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Общите условия<xliff:g id="END_TOS_LINK"></a></xliff:g> на Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Затваряне"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Начало"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Приложението се добавя на настолния компютър"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Отказ"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 948d07d..a0e32ef 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ফ্রি-ফর্ম"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনও সাম্প্রতিক আইটেম নেই"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"অ্যাপ ব্যবহারের সেটিংস"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"সবকিছু খালি করুন"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"\'টাস্কবার\' ফিচারের সাহায্যে আরও অনেক কিছু করুন"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"টাস্কবার সবসময় দেখানো"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"স্ক্রিনের নিচে টাস্কবার সবসময় দেখাতে ডিভাইডার টাচ করে ধরে থাকুন"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"আপনার স্ক্রিনে দেখতে পাওয়া কন্টেন্ট সার্চ করতে অ্যাকশন কী স্পর্শ করে ধরে রাখুন"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"সার্চ করার জন্য এই প্রোডাক্ট স্ক্রিনের বেছে নেওয়া অংশটুকু ব্যবহার করে। Google-এর <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>গোপনীয়তা নীতি<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> এবং <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>পরিষেবার শর্তাবলী<xliff:g id="END_TOS_LINK"></a></xliff:g> প্রযোজ্য।"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"আপনার স্ক্রিনে দেখতে পাওয়া কন্টেন্ট সার্চ করতে অ্যাকশন কী স্পর্শ করে ধরে রাখুন"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"সার্চ করার জন্য এই প্রোডাক্ট স্ক্রিনের বেছে নেওয়া অংশটুকু ব্যবহার করে। Google-এর <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>গোপনীয়তা নীতি<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> এবং <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>পরিষেবার শর্তাবলী<xliff:g id="END_TOS_LINK"></a></xliff:g> প্রযোজ্য।"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ করুন"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"হয়ে গেছে"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"হোম"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ডেস্কটপে অ্যাপ যোগ করা হচ্ছে"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"বাতিল করুন"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 15da445..08dafca 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodan oblik"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Uradite više pomoću trake zadataka"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stalni prikaz trake zadataka"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da se traka zadataka uvijek prikazuje na dnu ekrana, dodirnite i zadržite razdjelnik"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite tipku radnji da pretražite sadržaj na ekranu"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod koristi odabrani dio ekrana za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Pravila privatnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Uslovi korištenja usluge<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Dodirnite i zadržite tipku radnji da pretražite sadržaj na ekranu"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ovaj proizvod koristi odabrani dio ekrana za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Pravila privatnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Uslovi korištenja usluge<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Dom"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodavanje aplikacije na radnu površinu"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Otkaži"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 62ae01b..187d85a 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Treu més partit de la Barra de tasques"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostra sempre la Barra de tasques"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Perquè es mostri sempre la Barra de tasques a la part inferior de la pantalla, mantén premut el separador"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén premuda la tecla d\'acció per cercar què es mostra a la pantalla"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Aquest producte utilitza la part seleccionada de la pantalla per fer cerques. S\'apliquen la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>política de privadesa<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>condicions del servei<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén premuda la tecla d\'acció per cercar què es mostra a la pantalla"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Aquest producte utilitza la part seleccionada de la pantalla per fer cerques. S\'apliquen la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>política de privadesa<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>condicions del servei<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Tanca"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Fet"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Inici"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"S\'està afegint l\'aplicació a l\'ordinador"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel·la"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index eedcd45..ed32438 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Více možností s panelem aplikací"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stálé zobrazení panelu aplikací"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pokud chcete, aby se panel aplikací vždy zobrazoval ve spodní části obrazovky, podržte oddělovač."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Podržením akční klávesy můžete vyhledat obsah na obrazovce"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Tato služba používá k vyhledávání vybranou část obrazovky. Platí <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>zásady ochrany soukromí<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> a <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>smluvní podmínky<xliff:g id="END_TOS_LINK"></a></xliff:g> společnosti Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Podržením akční klávesy můžete vyhledat obsah na obrazovce"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Tato služba používá k vyhledávání vybranou část obrazovky. Platí <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>zásady ochrany soukromí<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> a <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>smluvní podmínky<xliff:g id="END_TOS_LINK"></a></xliff:g> společnosti Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Zavřít"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Domů"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Přidání aplikace na plochu"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Zrušit"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index a1ca3c5..250a3d3 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frit format"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computertilstand"</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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Få mere fra hånden med proceslinjen"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vis altid proceslinjen"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Hvis du vil have, at proceslinjen altid vises nederst på din skærm, skal du holde fingeren på skillelinjen"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Hold fingeren på handlingstasten for at søge efter det, der vises på din skærm"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dette produkt bruger den valgte del af din skærm til at søge. Googles <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privatlivspolitik<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> og <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>servicevilkår<xliff:g id="END_TOS_LINK"></a></xliff:g> er gældende."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Hold fingeren på handlingstasten for at søge efter det, der vises på din skærm"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dette produkt bruger den valgte del af din skærm til at søge. Googles <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privatlivspolitik<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> og <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>servicevilkår<xliff:g id="END_TOS_LINK"></a></xliff:g> er gældende."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Luk"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Luk"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Hjem"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Appen føjes til computeren"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuller"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 73c3f04..af35fc3 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -96,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Einstellungen der Systemsteuerung"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Teilen"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
- <string name="action_split" msgid="2098009717623550676">"Teilen"</string>
+ <string name="action_split" msgid="2098009717623550676">"Splitscreen"</string>
<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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Mehr Möglichkeiten mit der Taskleiste"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Taskleiste immer anzeigen"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Damit die Taskleiste immer unten angezeigt wird, halte den Teiler gedrückt"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Aktionstaste gedrückt halten, um auf dem Bildschirm zu suchen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dieses Produkt verwendet den ausgewählten Teil deines Bildschirms für die Suche. Es gelten die <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Datenschutzerklärung<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> und die <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Nutzungsbedingungen<xliff:g id="END_TOS_LINK"></a></xliff:g> von Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Aktionstaste gedrückt halten, um auf dem Bildschirm zu suchen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dieses Produkt verwendet den ausgewählten Teil deines Bildschirms für die Suche. Es gelten die <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Datenschutzerklärung<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> und die <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Nutzungsbedingungen<xliff:g id="END_TOS_LINK"></a></xliff:g> von Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Schließen"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Fertig"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Startbildschirm"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Hinzufügen einer App zum Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Abbrechen"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 55e535b..3bfe32a 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Κάντε περισσότερα με τη Γραμμή εργαλείων"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Να εμφανίζεται πάντα η Γραμμή εργαλείων"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Για να εμφανίζεται πάντα η Γραμμή εργαλείων στο κάτω μέρος της οθόνης, αγγίξτε παρατεταμένα το διαχωριστικό"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Αγγίξτε παρατεταμένα το πλήκτρο ενέργειας για να αναζητήσετε το περιεχόμενο της οθόνης"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Αυτό το προϊόν χρησιμοποιεί το επιλεγμένο τμήμα της οθόνης σας για αναζήτηση. Ισχύουν η <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Πολιτική απορρήτου<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> και οι <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Όροι Παροχής Υπηρεσιών<xliff:g id="END_TOS_LINK"></a></xliff:g> της Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Αγγίξτε παρατεταμένα το πλήκτρο ενέργειας για να αναζητήσετε το περιεχόμενο της οθόνης"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Αυτό το προϊόν χρησιμοποιεί το επιλεγμένο τμήμα της οθόνης σας για αναζήτηση. Ισχύουν η <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Πολιτική απορρήτου<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> και οι <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Όροι Παροχής Υπηρεσιών<xliff:g id="END_TOS_LINK"></a></xliff:g> της Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Κλείσιμο"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Τέλος"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Αρχική σελίδα"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Γίνεται προσθήκη εφαρμογής στον υπολογιστή"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Ακύρωση"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 8050284..a26779c 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch and hold the action key to search what\'s on your screen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch and hold the action key to search what\'s on your screen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 4daaa90..9539da6 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch & hold the divider"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch & hold the action key to search what\'s on your screen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch & hold the action key to search what\'s on your screen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -138,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 8050284..a26779c 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch and hold the action key to search what\'s on your screen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch and hold the action key to search what\'s on your screen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 8050284..a26779c 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch and hold the action key to search what\'s on your screen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch and hold the action key to search what\'s on your screen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 19e6aa0..f3499e1 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch & hold the divider"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch & hold the action key to search what\'s on your screen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Touch & hold the action key to search what\'s on your screen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> and <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Terms of Service<xliff:g id="END_TOS_LINK"></a></xliff:g> apply."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -138,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Adding app to Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancel"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index aa568f3..8214544 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Aprovecha mejor la Barra de tareas"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la Barra de tareas"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Mantén presionado el divisor para mostrar siempre la Barra de tareas en la parte inferior de la pantalla"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén presionada la tecla de acción para buscar qué hay en la pantalla"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Este producto usa la parte seleccionada de la pantalla para buscar. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y las <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Condiciones del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén presionada la tecla de acción para buscar qué hay en la pantalla"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este producto usa la parte seleccionada de la pantalla para buscar. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y las <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Condiciones del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Botón de inicio"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Agregando app al escritorio"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 27eceb8..0d43f1e 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Sácale más partido a la barra de tareas"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la barra de tareas"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar siempre la barra de tareas en la parte inferior, mantén pulsada la línea divisoria"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén pulsada la tecla de acción para buscar lo que ves en pantalla"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"El producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y los <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén pulsada la tecla de acción para buscar lo que ves en pantalla"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y los <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Hecho"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Añadiendo aplicación al ordenador"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index bffce79..c445bc8 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vabavorm"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Lauaarvuti režiim"</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>
@@ -91,12 +90,12 @@
<string name="allset_title" msgid="5021126669778966707">"Valmis!"</string>
<string name="allset_hint" msgid="459504134589971527">"Avalehele liikumiseks pühkige üles"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Avakuvale liikumiseks puudutage avakuva nuppu"</string>
- <string name="allset_description_generic" msgid="5385500062202019855">"Olete valmis oma seadet <xliff:g id="DEVICE">%1$s</xliff:g> kasutama"</string>
+ <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> on nüüd kasutamiseks valmis"</string>
<string name="default_device_name" msgid="6660656727127422487">"seade"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Süsteemi navigeerimisseaded"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
- <string name="action_split" msgid="2098009717623550676">"Eralda"</string>
+ <string name="action_split" msgid="2098009717623550676">"Jaga pooleks"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Tehke tegumiriba abil enamat"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Alati kuvatud tegumiriba"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Puudutage pikalt jaoturit, et tegumiriba oleks ekraani allosas alati kuvatud"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Puudutage pikalt toiminguklahvi, et ekraanil kuvatut otsida"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"See toode kasutab otsingu jaoks ekraani valitud osa. Kehtivad Google\'i <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privaatsuseeskirjad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ja <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>teenusetingimused<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Puudutage pikalt toiminguklahvi, et ekraanil kuvatut otsida"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"See toode kasutab otsingu jaoks ekraani valitud osa. Kehtivad Google\'i <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privaatsuseeskirjad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ja <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>teenusetingimused<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Sule"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Avaleht"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Rakenduse lisamine arvutisse"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Tühista"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 39fc489..3f56068 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Modu librea"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordenagailua"</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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Egin gauza gehiago zereginen barrarekin"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Erakutsi beti zereginen barra"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pantailaren behealdeko zereginen barra beti erakusteko, eduki sakatuta zatitzailea"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Eduki sakatuta ekintza-tekla pantailan dagoena bilatzeko"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produktu honek pantailan hautatutako zatia erabiltzen du bilaketa egiteko. Google-ren <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Pribatutasun-gidalerroak<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> eta <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Zerbitzu-baldintzak<xliff:g id="END_TOS_LINK"></a></xliff:g> aplikatzen dira."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Eduki sakatuta ekintza-tekla pantailan dagoena bilatzeko"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Produktu honek pantailan hautatutako zatia erabiltzen du bilaketa egiteko. Google-ren <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Pribatutasun-gidalerroak<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> eta <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Zerbitzu-baldintzak<xliff:g id="END_TOS_LINK"></a></xliff:g> aplikatzen dira."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Itxi"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Eginda"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Hasiera"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Aplikazioa mahaigainean gehitzen"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Utzi"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 958eecc..b6db375 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"رایانه"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"چیز جدیدی اینجا نیست"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"با «نوار وظیفه» میتوانید کارهای بیشتر انجام دهید"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"همیشه نشان داده شدن «نوار وظیفه»"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"برای اینکه «نوار وظیفه» همیشه در پایین صفحه نشان داده شود، تقسیمکننده را لمس کنید و نگه دارید"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"برای جستجوی محتوای صفحهنمایش، دکمه کنش را لمس کنید و نگه دارید"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"این محصول از قسمت انتخابشده صفحهنمایش شما برای جستجو استفاده میکند. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>خطمشی رازداری<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> و <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>شرایط خدمات<xliff:g id="END_TOS_LINK"></a></xliff:g> Google اعمال میشود."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"برای جستجوی محتوای صفحهنمایش، دکمه کنش را لمس کنید و نگه دارید"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"این محصول از قسمت انتخابشده صفحهنمایش شما برای جستجو استفاده میکند. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>خطمشی رازداری<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> و <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>شرایط خدمات<xliff:g id="END_TOS_LINK"></a></xliff:g> Google اعمال میشود."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"بستن"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"تمام"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"صفحه اصلی"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"درحال افزودن برنامه به رایانه"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"لغو"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 40c4fc2..040976d 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vapaamuotoinen"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -96,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Järjestelmän navigointiasetukset"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Jaa"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
- <string name="action_split" msgid="2098009717623550676">"Jaa"</string>
+ <string name="action_split" msgid="2098009717623550676">"Jaettu näyttö"</string>
<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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Vinkkejä tehtäväpalkin tehokkaampaan käyttöön"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Näytä tehtäväpalkki aina"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Jos haluat tehtäväpalkin näkyvän aina näytön alaosassa, kosketa jakajaa pitkään"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Kosketa toimintonäppäintä pitkään, niin voit tehdä haun näytöltäsi"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Tämä tuote käyttää hakuun näytön valittua osaa. Tähän sovelletaan Googlen <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>tietosuojakäytäntöä<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ja <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>käyttöehtoja<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Kosketa toimintonäppäintä pitkään, niin voit hakea näytöltä"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Tämä tuote käyttää hakuun valittua näytön osaa. Tähän sovelletaan Googlen <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>tietosuojakäytäntöä<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ja <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>käyttöehtoja<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Sulje"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Etusivu"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Sovelluksen lisääminen työpöydälle"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Peru"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 10aa359..9c30dc5 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Toujours afficher la Barre des tâches"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pour toujours afficher la Barre des tâches en bas de l\'écran, maintenez le doigt sur le séparateur"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Maintenez le doigt sur la touche d\'action pour rechercher ce qui se trouve sur votre écran"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ce produit utilise la partie sélectionnée de votre écran pour effectuer une recherche. La <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>politique de confidentialité<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> et les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>conditions d\'utilisation<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google s\'appliquent."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Maintenez le doigt sur la touche d\'action pour rechercher ce qui se trouve sur votre écran"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ce produit utilise la partie sélectionnée de votre écran pour effectuer une recherche. La <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>politique de confidentialité<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> et les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>conditions d\'utilisation<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google s\'appliquent."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Accueil"</string>
@@ -138,6 +138,7 @@
<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 application.}one{Afficher # autre application.}other{Afficher # autres applications.}}"</string>
+ <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Ajout de l\'application au bureau en cours…"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuler"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 457d425..72a6334 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Toujours afficher la barre des tâches"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pour toujours afficher la barre des tâches en bas de votre écran, appuyez sur le séparateur de manière prolongée."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Appuyez de manière prolongée sur la touche d\'action pour rechercher ce qui se trouve à l\'écran"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ce produit utilise la zone sélectionnée de l\'écran pour rechercher. Les <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Règles de confidentialité<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> et les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Conditions d\'utilisation<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google s\'appliquent."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Appuyez de manière prolongée sur la touche d\'action pour rechercher ce qui se trouve à l\'écran"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ce produit utilise la zone sélectionnée de l\'écran pour rechercher. Les <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Règles de confidentialité<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> et les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Conditions d\'utilisation<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google s\'appliquent."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Accueil"</string>
@@ -138,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Ajout de l\'appli au bureau"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuler"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 0be8958..2c06c8f 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Tira máis proveito da barra de tarefas"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar sempre a barra de tarefas"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para fixar a barra de tarefas na parte inferior, mantén premida a liña divisoria"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén premida a tecla de acción para buscar o que hai na pantalla"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Este produto utiliza a parte seleccionada da pantalla para facer buscas. Aplícanse as <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Condicións de servizo<xliff:g id="END_TOS_LINK"></a></xliff:g> e a <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de privacidade<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> de Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén premida a tecla de acción para buscar o que hai na pantalla"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este produto utiliza a parte seleccionada da pantalla para facer buscas. Aplícanse as <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Condicións de servizo<xliff:g id="END_TOS_LINK"></a></xliff:g> e a <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de privacidade<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> de Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Pechar"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Engadindo aplicación ao ordenador"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 644240a..25285cb 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ફ્રિફોર્મ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ડેસ્કટૉપ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ઍપ વપરાશનું સેટિંગ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"બધું સાફ કરો"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ટાસ્કબાર વડે બીજું ઘણું કરો"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ટાસ્કબાર હંમેશાં બતાવો"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ટાસ્કબાર હંમેશાં તમારી સ્ક્રીનમાં સૌથી નીચે દેખાય તે માટે વિભાજકને ટચ કરીને થોડીવાર દબાવી રાખો"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"તમારી સ્ક્રીન પર જે હોય તે શોધવા માટે, ઍક્શન કી ટચ કરીને દબાવી રાખો"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"શોધવા માટે, આ પ્રોડક્ટ તમારી સ્ક્રીનના પસંદ કરેલા ભાગનો ઉપયોગ કરે છે. Googleની <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>પ્રાઇવસી પૉલિસી<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> અને <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>સેવાની શરતો<xliff:g id="END_TOS_LINK"></a></xliff:g> લાગુ થાય છે."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"તમારી સ્ક્રીન પર જે હોય તે શોધવા માટે, ઍક્શન કી ટચ કરીને દબાવી રાખો"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"શોધવા માટે, આ પ્રોડક્ટ તમારી સ્ક્રીનના પસંદ કરેલા ભાગનો ઉપયોગ કરે છે. Googleની <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>પ્રાઇવસી પૉલિસી<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> અને <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>સેવાની શરતો<xliff:g id="END_TOS_LINK"></a></xliff:g> લાગુ થાય છે."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"બંધ કરો"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"થઈ ગયું"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"હોમ"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ડેસ્કટૉપ પર ઍપ ઉમેરી રહ્યાં છીએ"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"રદ કરો"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index b2da5db..d40b0b4 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करें"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ़्रीफ़ॉर्म"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हाल ही का कोई आइटम नहीं है"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ऐप्लिकेशन इस्तेमाल की सेटिंग"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सभी हटाएं"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार के साथ कई और काम करें"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार को हमेशा दिखाएं"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"टास्कबार को हमेशा अपनी स्क्रीन के नीचे दिखाने के लिए, डिवाइडर दबाकर रखें"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"स्क्रीन में दिख रहे कॉन्टेंट को खोजने के लिए, ऐक्शन बटन को दबाकर रखें"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"यह प्रॉडक्ट, कॉन्टेंट खोजने के लिए स्क्रीन पर चुनिंदा हिस्से का इस्तेमाल करता है. Google की <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>निजता नीति<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> और <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>सेवा की शर्तें<xliff:g id="END_TOS_LINK"></a></xliff:g> लागू होती हैं."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"स्क्रीन पर दिख रहे कॉन्टेंट को खोजने के लिए, ऐक्शन बटन को दबाकर रखें"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"यह प्रॉडक्ट, स्क्रीन के चुनिंदा हिस्से पर कॉन्टेंट खोजता है. Google की <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>निजता नीति<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> और <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>सेवा की शर्तें<xliff:g id="END_TOS_LINK"></a></xliff:g> लागू."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"बंद करें"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"हो गया"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"डेस्कटॉप पर ऐप्लिकेशन जोड़ा जा रहा है"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"रद्द करें"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index b68d961..5f7bc70 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računalo"</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>
@@ -91,12 +90,12 @@
<string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string>
<string name="allset_hint" msgid="459504134589971527">"Prijeđite prstom prema gore da biste otvorili početni zaslon"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite gumb početnog zaslona da biste prešli na početni zaslon"</string>
- <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste za početak upotrebe uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+ <string name="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="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>
- <string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
+ <string name="action_split" msgid="2098009717623550676">"Podjela"</string>
<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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Učinite više pomoću trake sa zadacima"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Uvijek prikazuj traku sa zadacima"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da bi se traka prikazivala, dodirnite i držite razdjelnik"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite tipku za radnju da biste pretražili što se nalazi na zaslonu"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod upotrebljava odabrani dio zaslona za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>pravila o privatnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>uvjeti pružanja usluge<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Dodirnite i zadržite tipku za radnju da biste pretražili što se nalazi na zaslonu"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ovaj proizvod upotrebljava odabrani dio zaslona za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>pravila o privatnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>uvjeti pružanja usluge<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodavanje aplikacije na radnu površinu"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Odustani"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index fe629dd..7ce1f02 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Jobban kihasználhatja a Feladatsávot"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mindig jelenjen meg a Feladatsáv"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ahhoz, hogy a Feladatsáv mindig megjelenjen a képernyő alján, érintse meg és tartsa lenyomva az elválasztót"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"A műveletbillentyűt lenyomva tartva kereshet a képernyőn található tartalmak között"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ez a termék a képernyő kiválasztott részét használja a kereséshez. A Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Adatvédelmi irányelvei<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> és <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Általános Szerződési Feltételei<xliff:g id="END_TOS_LINK"></a></xliff:g> érvényesek."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"A műveletbillentyűt lenyomva tartva kereshet a képernyőn található tartalmak között"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ez a termék a képernyő kiválasztott részét használja a kereséshez. A Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Adatvédelmi irányelvei<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> és <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Általános Szerződési Feltételei<xliff:g id="END_TOS_LINK"></a></xliff:g> érvényesek."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Bezárás"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Kész"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Kezdőlap"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Alkalmazás hozzáadása az asztalhoz"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Mégse"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index e0646aa..b89cd3c 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Կամայական ձև"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Համակարգիչ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Այստեղ դեռ ոչինչ չկա"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Հավելվածի օգտագործման կարգավորումներ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Օգտվեք հավելվածների վահանակի բոլոր հնարավորություններից"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Ամրացրեք հավելվածների վահանակը"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Հավելվածների վահանակն էկրանի ներքևում ամրացնելու համար հպեք և պահեք բաժանիչը"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Սեղմած պահեք գործողության ստեղնը՝ էկրանին բովանդակություն որոնելու համար"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Այս պրոդուկտն օգտագործում է էկրանի ընտրված հատվածը որոնման համար։ Կիրառվում են Google-ի <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>գաղտնիության քաղաքականությունը<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> և <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>օգտագործման պայմանները<xliff:g id="END_TOS_LINK"></a></xliff:g>։"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Սեղմած պահեք գործողության ստեղնը՝ էկրանին բովանդակություն որոնելու համար"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Այս պրոդուկտն օգտագործում է էկրանի ընտրված հատվածը որոնման համար։ Կիրառվում են Google-ի <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Գաղտնիության քաղաքականությունը<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> և <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Օգտագործման պայմանները<xliff:g id="END_TOS_LINK"></a></xliff:g>։"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Փակել"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Պատրաստ է"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Սկիզբ"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Հավելվածն ավելացվում է աշխատասեղանին"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Չեղարկել"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index eec7e10..aaf6ced 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan lebih banyak hal dengan Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Selalu tampilkan Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Untuk selalu menampilkan Taskbar di bagian bawah layar Anda, sentuh & tahan pembatasnya"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Sentuh & tahan tombol tindakan untuk mencari konten di layar Anda"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produk ini menggunakan bagian layar terpilih untuk menelusuri. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Kebijakan Privasi<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> dan <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Persyaratan Layanan<xliff:g id="END_TOS_LINK"></a></xliff:g> Google berlaku."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Sentuh & tahan tombol tindakan untuk mencari konten di layar Anda"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Produk ini menggunakan bagian layar terpilih untuk menelusuri. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Kebijakan Privasi<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> dan <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Persyaratan Layanan<xliff:g id="END_TOS_LINK"></a></xliff:g> Google berlaku."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Layar utama"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Menambahkan aplikasi ke Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Batalkan"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index e023124..d008af6 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Nýttu forritastikuna betur"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Halda forritastikunni sýnilegri"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Haltu skjáskiptingunni neðst á skjánum inni til að halda forritastikunni sýnilegri"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Haltu aðgerðalyklinum inni til að leita að því sem er á skjánum"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Þessi vara notar valinn hluta skjásins til að leita. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Persónuverndarstefna<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> og <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>þjónustuskilmálar<xliff:g id="END_TOS_LINK"></a></xliff:g> Google gilda."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Haltu aðgerðalyklinum inni til að leita að því sem er á skjánum"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Þessi vara notar valinn hluta skjásins til að leita. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Persónuverndarstefna<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> og <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>þjónustuskilmálar<xliff:g id="END_TOS_LINK"></a></xliff:g> Google gilda."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Loka"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Lokið"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Heim"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Forriti bætt við skjáborð"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Hætta við"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index f66761f..207c182 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Fai di più con la barra delle app"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostra sempre la barra delle app"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Per mostrare sempre la barra delle app in basso, tocca e tieni premuto il divisore"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Tocca e tieni premuto il tasto azione per cercare gli elementi sullo schermo"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Il prodotto usa la parte selezionata dello schermo per cercare. Si applicano le <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Norme sulla privacy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> e i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termini di servizio<xliff:g id="END_TOS_LINK"></a></xliff:g> di Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Tocca e tieni premuto il tasto azione per cercare gli elementi sullo schermo"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Il prodotto usa la parte selezionata dello schermo per cercare. Si applicano le <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Norme sulla privacy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> e i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termini di servizio<xliff:g id="END_TOS_LINK"></a></xliff:g> di Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Chiudi"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Fine"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Aggiunta app a desktop in corso…"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annulla"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index a424bcd..9be2c1a 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"מצב חופשי"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"במחשב"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"הגדרות שימוש באפליקציה"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ניקוי הכול"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"פעולות נוספות שאפשר לעשות עם סרגל האפליקציות"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"תמיד להציג את סרגל האפליקציות"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"כדי להציג תמיד את סרגל האפליקציות בתחתית המסך, יש ללחוץ לחיצה ארוכה על המחיצה"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"כדי לחפש במסך, צריך ללחוץ לחיצה ארוכה על מקש הפעולה"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"המוצר הזה משתמש בחלק שבחרת במסך לצורך חיפוש, בכפוף ל<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>מדיניות הפרטיות<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ו<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>התנאים וההגבלות<xliff:g id="END_TOS_LINK"></a></xliff:g> של Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"כדי לחפש במסך, צריך ללחוץ לחיצה ארוכה על מקש הפעולה"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"המוצר הזה משתמש בחלק שבחרת במסך לצורך חיפוש, בכפוף ל<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>מדיניות הפרטיות<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ו<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>לתנאים ולהגבלות<xliff:g id="END_TOS_LINK"></a></xliff:g> של Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"סגירה"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"סיום"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"בית"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"האפליקציה מתווספת לשולחן העבודה"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ביטול"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index b0b1190..084f2b2 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"フリーフォーム"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"パソコン"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"タスクバーの各種機能"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"タスクバーを常に表示"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"タスクバーを画面下部に常に表示するには分割線を長押しします"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"画面上の内容を検索するには、アクションキーを長押ししてください"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"このサービスは、検索する際に画面上で選択された箇所を使用します。Google の<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>プライバシー ポリシー<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>と<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>利用規約<xliff:g id="END_TOS_LINK"></a></xliff:g>が適用されます。"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"画面上の内容を検索するには、アクションキーを長押ししてください"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"このサービスは、検索する際に画面上で選択された箇所を使用します。Google の<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>プライバシー ポリシー<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>と<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>利用規約<xliff:g id="END_TOS_LINK"></a></xliff:g>が適用されます。"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"閉じる"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"完了"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ホーム"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"アプリをデスクトップに追加する"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"キャンセル"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 4306f1f..b6890c4 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"გააკეთეთ მეტი ამოცანათა ზოლის მეშვეობით"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ამოცანათა ზოლის მუდმივად ჩვენება"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"თქვენი ეკრანის ქვედა ნაწილში ამოცანათა ზოლის მუდმივად საჩვენებლად, ხანგრძლივად შეეხეთ გამყოფს"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"შეეხეთ და გეჭიროთ მოქმედების კლავიში, რათა მოძებნოთ ის, რაც თქვენს ეკრანზეა"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ეს პროდუქტი ძიებისთვის იყენებს თქვენი ეკრანის არჩეულ ნაწილს. მოქმედებს Google-ის <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>კონფიდენციალურობის დებულება<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> და <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>მომსახურებს პირობები<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"შეეხეთ და გეჭიროთ მოქმედების ღილაკი, რათა მოძებნოთ ის, რაც თქვენს ეკრანზეა"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ეს პროდუქტი ძიებისთვის იყენებს თქვენი ეკრანის არჩეულ ნაწილს. მოქმედებს Google-ის <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>კონფიდენციალურობის დებულება<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> და <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>მომსახურებს პირობები<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"დახურვა"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"მზადაა"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"მთავარი"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"მიმდინარეობს აპის დესკტოპზე დამატება"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"გაუქმება"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 2a12452..36f3490 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Еркін форма"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Қолданбаны пайдалану параметрлері"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Тапсырмалар жолағында мүмкіндік көп"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапсырмалар жолағын әрдайым көрсету"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Экранның төменгі жағында тапсырмалар жолағы әрдайым көрсетілуі үшін, бөлгішті басып тұрыңыз."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Экраннан іздеу үшін әрекет пернесін басып тұрыңыз"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Бұл өнім іздеу үшін экранның таңдалған бөлігін пайдаланады. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Құпиялық саясаты<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> мен <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Қызмет көрсету шарттары<xliff:g id="END_TOS_LINK"></a></xliff:g> қолданылады."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Экраннан іздеу үшін әрекет пернесін басып тұрыңыз"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Бұл өнім іздеу үшін экранның таңдалған бөлігін пайдаланады. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Құпиялық саясаты<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> мен <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Қызмет көрсету шарттары<xliff:g id="END_TOS_LINK"></a></xliff:g> қолданылады."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Дайын"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Негізгі экран"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Жұмыс үстеліне қолданба қосу"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Бас тарту"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index bcec955..98a97e7 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ធ្វើបានកាន់តែច្រើនដោយប្រើរបារកិច្ចការ"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"បង្ហាញរបារកិច្ចការជានិច្ច"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ដើម្បីបង្ហាញរបារកិច្ចការនៅផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នកជានិច្ច សូមចុចបន្ទាត់ខណ្ឌចែកឱ្យជាប់"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ចុចគ្រាប់ចុចសកម្មភាពឱ្យជាប់ ដើម្បីស្វែងរកអ្វីដែលមាននៅលើអេក្រង់របស់អ្នក"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ផលិតផលនេះប្រើប្រាស់ផ្នែកដែលបានជ្រើសរើសនៃអេក្រង់របស់អ្នក ដើម្បីស្វែងរក។ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>គោលការណ៍ឯកជនភាព<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> និង<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>លក្ខខណ្ឌប្រើប្រាស់<xliff:g id="END_TOS_LINK"></a></xliff:g>របស់ Google ត្រូវបានអនុវត្ត។"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ចុចគ្រាប់ចុចសកម្មភាពឱ្យជាប់ ដើម្បីស្វែងរកអ្វីដែលមាននៅលើអេក្រង់របស់អ្នក"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ផលិតផលនេះប្រើប្រាស់ផ្នែកដែលបានជ្រើសរើសនៃអេក្រង់របស់អ្នក ដើម្បីស្វែងរក។ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>គោលការណ៍ឯកជនភាព<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> និង<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>លក្ខខណ្ឌប្រើប្រាស់<xliff:g id="END_TOS_LINK"></a></xliff:g>របស់ Google ត្រូវបានអនុវត្ត។"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"បិទ"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"រួចរាល់"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ទំព័រដើម"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"កំពុងបញ្ចូលកម្មវិធីទៅកុំព្យូទ័រ"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"បោះបង់"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index c7c6389..7b1241f 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ಮುಕ್ತಸ್ವರೂಪ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ಡೆಸ್ಕ್ಟಾಪ್"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ಆ್ಯಪ್ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ಟಾಸ್ಕ್ಬಾರ್ ಮೂಲಕ ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ಯಾವಾಗಲೂ ಟಾಸ್ಕ್ಬಾರ್ ಅನ್ನು ತೋರಿಸಿ"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ಯಾವಾಗಲೂ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಲ್ಲಿ ಟಾಸ್ಕ್ ಬಾರ್ ಅನ್ನು ತೋರಿಸಲು, ಡಿವೈಡರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಮೇಲೆ ಏನಿದೆ ಎಂಬುದನ್ನು ಹುಡುಕಲು ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ಈ ಉತ್ಪನ್ನವು ಹುಡುಕಲು ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಆಯ್ದ ಭಾಗವನ್ನು ಬಳಸುತ್ತದೆ. Google ನ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ಗೌಪ್ಯತೆ ನೀತಿ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ಮತ್ತು <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ಸೇವಾ ನಿಯಮಗಳು<xliff:g id="END_TOS_LINK"></a></xliff:g> ಅನ್ವಯಿಸುತ್ತವೆ."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಮೇಲೆ ಏನಿದೆ ಎಂಬುದನ್ನು ಹುಡುಕಲು ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ಈ ಉತ್ಪನ್ನವು ಹುಡುಕಲು ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಆಯ್ದ ಭಾಗವನ್ನು ಬಳಸುತ್ತದೆ. Google ನ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ಗೌಪ್ಯತೆ ನೀತಿ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ಮತ್ತು <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ಸೇವಾ ನಿಯಮಗಳು<xliff:g id="END_TOS_LINK"></a></xliff:g> ಅನ್ವಯಿಸುತ್ತವೆ."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ಮುಚ್ಚಿರಿ"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ಆಯಿತು"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ಮುಖಪುಟ"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ಡೆಸ್ಕ್ಟಾಪ್ಗೆ ಆ್ಯಪ್ ಅನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ರದ್ದುಮಾಡಿ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 0fba87d..5f05968 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"고정"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"자유 형식"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"데스크톱"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"최근 항목이 없습니다."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"앱 사용 설정"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"모두 삭제"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"태스크 바 최대한 활용하기"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"태스크 바 항상 표시"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"화면 하단에 태스크 바를 항상 표시하려면 구분선을 길게 터치하세요."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"화면 내용을 검색하려면 작업 키 길게 터치"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"이 제품은 사용자가 화면에서 선택한 부분을 사용하여 검색하며, Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>개인정보처리방침<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> 및 <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>서비스 약관<xliff:g id="END_TOS_LINK"></a></xliff:g>이 적용됩니다."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"화면 내용을 검색하려면 작업 키 길게 터치"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"이 제품은 사용자가 화면에서 선택한 부분을 사용하여 검색하며, Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>개인정보처리방침<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> 및 <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>서비스 약관<xliff:g id="END_TOS_LINK"></a></xliff:g>이 적용됩니다."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"닫기"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"완료"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"홈"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"데스크톱에 앱 추가하기"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"취소"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 061952c..993e4ea 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Эркин форма режими"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Колдонмону пайдалануу параметрлери"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Баарын тазалоо"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Тапшырмалар тактасы менен көбүрөөк иш бүтүрөсүз"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапшырмалар панелин ар дайым көрсөтүү"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Тапшырмалар панелин экрандын ылдый жагында ар дайым көрсөтүү үчүн бөлгүчтү коё бербей басыңыз"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Экрандагы нерсени издөө үчүн аракет баскычын коё бербей кармап туруңуз"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Бул кызмат издөө үчүн экранда тандалган бөлүктү колдонот. Google\'дун <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Купуялык эрежелери<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> жана <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Тейлөө шарттары<xliff:g id="END_TOS_LINK"></a></xliff:g> колдонулат."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Экрандагы нерсени издөө үчүн аракет баскычын коё бербей кармап туруңуз"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Бул кызмат издөө үчүн экранда тандалган бөлүктү колдонот. Google\'дун <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Купуялык эрежелери<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> жана <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Тейлөө шарттары<xliff:g id="END_TOS_LINK"></a></xliff:g> колдонулат."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Жабуу"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Бүттү"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Башкы бет"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Колдонмону иш тактага кошуу"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Жокко чыгаруу"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 9496dd5..2d5a5cc 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ເຮັດສິ່ງຕ່າງໆໄດ້ຫຼາຍຂຶ້ນດ້ວຍແຖບໜ້າວຽກ"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ສະແດງແຖບໜ້າວຽກສະເໝີ"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ເພື່ອໃຫ້ແຖບໜ້າວຽກສະແດງຢູ່ລຸ່ມໜ້າຈໍຂອງທ່ານຢູ່ສະເໝີ, ໃຫ້ແຕະຕົວແບ່ງຄ້າງໄວ້"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ແຕະປຸ່ມຄຳສັ່ງຄ້າງໄວ້ເພື່ອຊອກຫາສິ່ງທີ່ຢູ່ເທິງໜ້າຈໍຂອງທ່ານ"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ສິນຄ້ານີ້ໃຊ້ສ່ວນທີ່ເລືອກຂອງໜ້າຈໍຂອງທ່ານເພື່ອຊອກຫາ. ເປັນໄປຕາມ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ນະໂຍບາຍຄວາມເປັນສ່ວນຕົວ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ແລະ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ຂໍ້ກຳນົດບໍລິການ<xliff:g id="END_TOS_LINK"></a></xliff:g> ຂອງ Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ແຕະປຸ່ມຄຳສັ່ງຄ້າງໄວ້ເພື່ອຊອກຫາສິ່ງທີ່ຢູ່ເທິງໜ້າຈໍຂອງທ່ານ"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ສິນຄ້ານີ້ໃຊ້ສ່ວນທີ່ເລືອກຂອງໜ້າຈໍຂອງທ່ານເພື່ອຊອກຫາ. ເປັນໄປຕາມ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ນະໂຍບາຍຄວາມເປັນສ່ວນຕົວ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ແລະ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ຂໍ້ກຳນົດບໍລິການ<xliff:g id="END_TOS_LINK"></a></xliff:g> ຂອງ Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ປິດ"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ແລ້ວໆ"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ໜ້າຫຼັກ"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ການເພີ່ມແອັບໄປໃສ່ເດັສທັອບ"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ຍົກເລີກ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index c8a031f..232e7e7 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Atlikite daugiau naudodami Užduočių juostą"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Visada rodyti užduočių juostą"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Jei norite, kad užduočių juosta visada būtų rodoma ekrano apačioje, palieskite ir palaikykite daliklį"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekrane rodomo turinio paieška palietus ir laikant veiksmų klavišą"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Šis produktas paieškai naudoja pasirinktą ekrano dalį. Taikomos „Google“ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privatumo politikos<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ir <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>paslaugų teikimo sąlygos<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekrane rodomo turinio paieška palietus ir laikant veiksmų klavišą"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Šis produktas paieškai naudoja pasirinktą ekrano dalį. Taikomos „Google“ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>privatumo politikos<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ir <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>paslaugų teikimo sąlygos<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Uždaryti"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Atlikta"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Pagrindinis"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Pridedama programa prie darbalaukio"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Atšaukti"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 276120b..d602676 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Brīva forma"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Dators"</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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Plašākas iespējas, izmantojot uzdevumu joslu"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vienmēr rādīt uzdevumu joslu"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Lai uzdevumu joslu rādītu apakšdaļā, pieskarieties atdalītājam un turiet"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Pieskarieties darbību taustiņam un turiet to, lai meklētu ekrānā redzamo saturu"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Šis produkts meklēšanai izmanto atlasīto ekrāna daļu. Ir spēkā Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>konfidencialitātes politika<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> un <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>pakalpojumu sniegšanas noteikumi<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Pieskarieties darbību taustiņam un turiet to, lai meklētu ekrānā redzamo saturu"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Šajā produktā atlasītā ekrāna daļa tiek izmantota meklēšanai. Ir spēkā Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>konfidencialitātes politika<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> un <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>pakalpojumu sniegšanas noteikumi<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Aizvērt"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Gatavs"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Sākums"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Notiek lietotnes pievienošana datoram"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Atcelt"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 539448d..3d1196a 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компјутер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Поставки за користење на апликациите"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Избриши ги сите"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Правете сешто со „Лентата со задачи“"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Како секогаш да се прикажува „Лентата со задачи“"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Допрете и задржете го разделникот за да може „Лентата со задачи“ секогаш да се прикажува на дното на екранот"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Допрете и задржете го копчето за дејство за да пребарувате на екранот"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Производов го користи избраниот дел од екранот за пребарување. Важат <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Политиката за приватност<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Условите за користење<xliff:g id="END_TOS_LINK"></a></xliff:g> на Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Допрете и задржете го копчето за дејство за да пребарувате на екранот"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Производов го користи избраниот дел од екранот за пребарување. Важат <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Политиката за приватност<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Условите за користење<xliff:g id="END_TOS_LINK"></a></xliff:g> на Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Дома"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Додавање на апликацијата во „Работна површина“"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Откажи"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 17380a0..8194897 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ഫ്രീഫോം"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ഡെസ്ക്ടോപ്പ്"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ആപ്പ് ഉപയോഗ ക്രമീകരണം"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്ക്കുക"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ടാസ്ക്ബാർ ഉപയോഗിച്ച് കൂടുതൽ ചെയ്യുക"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"എല്ലായ്പ്പോഴും ടാസ്ക്ബാർ കാണിക്കുക"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ടാസ്ക്ബാർ എല്ലായ്പ്പോഴും നിങ്ങളുടെ സ്ക്രീനിന്റെ ചുവടെ കാണിക്കുന്നതിന് ഡിവൈഡറിൽ സ്പർശിച്ച് പിടിക്കുക"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"നിങ്ങളുടെ സ്ക്രീനിൽ എന്താണ് ഉള്ളതെന്ന് തിരയാൻ ആക്ഷൻ കീ സ്പർശിച്ച് പിടിക്കുക"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"തിരയുന്നതിന് ഈ ഉൽപ്പന്നം സ്ക്രീനിലെ തിരഞ്ഞെടുത്ത ഭാഗം ഉപയോഗിക്കുന്നു. Google-ന്റെ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>സ്വകാര്യതാ നയവും<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>സേവന നിബന്ധനകളും<xliff:g id="END_TOS_LINK"></a></xliff:g> ബാധകമാണ്."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"നിങ്ങളുടെ സ്ക്രീനിൽ എന്താണ് ഉള്ളതെന്ന് തിരയാൻ ആക്ഷൻ കീ സ്പർശിച്ച് പിടിക്കുക"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"തിരയുന്നതിന് ഈ ഉൽപ്പന്നം സ്ക്രീനിലെ തിരഞ്ഞെടുത്ത ഭാഗം ഉപയോഗിക്കുന്നു. Google-ന്റെ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>സ്വകാര്യതാ നയവും<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>സേവന നിബന്ധനകളും<xliff:g id="END_TOS_LINK"></a></xliff:g> ബാധകമാണ്."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"അടയ്ക്കുക"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"പൂർത്തിയായി"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ഹോം"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ആപ്പ് ഡെസ്ക്ടോപ്പിലേക്ക് ചേർക്കുന്നു"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"റദ്ദാക്കുക"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index c021d21..7b4337c 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бэхлэх"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Чөлөөтэй хувьсах"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Апп ашиглалтын тохиргоо"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Бүгдийг арилгах"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Ажлын хэсгийн тусламжтай илүү ихийг хийгээрэй"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Ажлын хэсгийг үргэлж харуулах"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Дэлгэцийнхээ доод талд Ажлын хэсгийг үргэлж харуулахын тулд хуваагч дээр хүрээд удаан дарна уу"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Дэлгэц дээрээ байгаа зүйлийг хайхын тулд тусгай товчлуурыг удаан дарна уу"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Энэ бүтээгдэхүүн хайхын тулд таны дэлгэцийн сонгосон хэсгийг ашигладаг. Google-н <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>нууцлалын бодлого<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> болон <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>үйлчилгээний нөхцөл<xliff:g id="END_TOS_LINK"></a></xliff:g> хэрэгжинэ."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Дэлгэц дээрээ байгаа зүйлийг хайхын тулд тусгай товчлуурыг удаан дарна уу"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Энэ бүтээгдэхүүн хайхын тулд таны дэлгэцийн сонгосон хэсгийг ашигладаг. Google-н <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>нууцлалын бодлого<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> болон <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>үйлчилгээний нөхцөл<xliff:g id="END_TOS_LINK"></a></xliff:g> хэрэгжинэ."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Хаах"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Дууссан"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Гэр"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Компьютерт апп нэмж байна"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Цуцлах"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index fa09e2b..453de89 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रीफॉर्म"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अॅप वापर सेटिंग्ज"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार चा पुरेपूर वापर करा"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार नेहमी दाखवा"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"टास्कबार नेहमी तुमच्या स्क्रीनच्या तळाशी दाखवण्यासाठी, विभाजकाला स्पर्श करून धरून ठेवा"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"तुमच्या स्क्रीनवर काय आहे हे शोधण्यासाठी अॅक्शन की स्पर्श करून धरून ठेवा"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"शोधण्यासाठी हे उत्पादन तुमच्या स्क्रीनचा निवडलेला भाग वापरते. Google चे <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>गोपनीयता धोरण<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> आणि <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>सेवा अटी<xliff:g id="END_TOS_LINK"></a></xliff:g> लागू होतात."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"तुमच्या स्क्रीनवरील गोष्टी शोधण्यासाठी अॅक्शन की स्पर्श करून धरून ठेवा"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"हे उत्पादन शोधण्याच्या हेतूसाठी तुमच्या स्क्रीनचा निवडक भाग वापरते. Google चे <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>गोपनीयता धोरण<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> आणि <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>सेवा अटी<xliff:g id="END_TOS_LINK"></a></xliff:g> लागू होतात."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"बंद करा"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"पूर्ण झाले"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"डेस्कटॉपवर ॲप जोडत आहे"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"रद्द करा"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index d998176..cbc1594 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan lebih banyak perkara dengan Bar Tugas"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Sentiasa paparkan Bar Tugas"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Untuk sentiasa memaparkan Bar Tugas pada bahagian bawah skrin, sentuh & tahan pembahagi"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Sentuh & tahan kekunci tindakan untuk mencari kandungan yang dipaparkan pada skrin anda"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produk ini menggunakan bahagian yang dipilih pada skrin untuk membuat carian. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Dasar Privasi<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> dan <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Syarat Perkhidmatan<xliff:g id="END_TOS_LINK"></a></xliff:g> Google digunakan."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Sentuh & tahan kekunci tindakan untuk mencari kandungan yang dipaparkan pada skrin anda"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Produk ini menggunakan bahagian yang dipilih pada skrin anda untuk membuat carian. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Dasar Privasi<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> dan <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Syarat Perkhidmatan<xliff:g id="END_TOS_LINK"></a></xliff:g> Google digunakan."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Laman Utama"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Menambahkan apl pada Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Batal"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 66c4e5f..ecde5a3 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးရန်"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"အလွတ်ပုံစံ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ဒက်စ်တော့"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးရှင်းရန်"</string>
@@ -96,7 +95,7 @@
<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_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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Taskbar ဖြင့် ပိုမိုလုပ်ဆောင်နိုင်ခြင်း"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Taskbar ကို အမြဲပြပါ"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Taskbar ကို စခရင်အောက်ခြေတွင် အမြဲပြရန် ခွဲခြားမျဉ်းကို တို့ထိ၍ ဖိထားပါ"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"သင့်စခရင်ပေါ်ရှိအရာကို ရှာရန် လုပ်ဆောင်ချက်ကီးကို ထိ၍ဖိထားပါ"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ဤကုန်ပစ္စည်းသည် သင့်စခရင်၌ ရွေးထားသောအပိုင်းကိုသုံး၍ ရှာဖွေသည်။ Google ၏ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ကိုယ်ရေးအချက်အလက်လုံခြုံမှုဆိုင်ရာ မူဝါဒ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> နှင့် <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ဝန်ဆောင်မှုစည်းမျဉ်းများ<xliff:g id="END_TOS_LINK"></a></xliff:g> အကျုံးဝင်သည်။"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"သင့်စခရင်ပေါ်ရှိအရာကို ရှာရန် လုပ်ဆောင်ချက်ကီးကို ထိ၍ဖိထားပါ"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ဤကုန်ပစ္စည်းသည် သင့်စခရင်၌ ရွေးထားသောအပိုင်းကိုသုံး၍ ရှာဖွေသည်။ Google ၏ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ကိုယ်ရေးအချက်အလက်လုံခြုံမှုဆိုင်ရာ မူဝါဒ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> နှင့် <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ဝန်ဆောင်မှုစည်းမျဉ်းများ<xliff:g id="END_TOS_LINK"></a></xliff:g> အကျုံးဝင်သည်။"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ပိတ်ရန်"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ပြီးပြီ"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ပင်မစာမျက်နှာ"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"‘ဒက်စ်တော့’ တွင် အက်ပ်ကို ထည့်ခြင်း"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"မလုပ်တော့"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 6f9f38c..5ea50f4 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Gjør mer med oppgavelinjen"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vis alltid oppgavelinjen"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"For å alltid vise oppgavelinjen nederst på skjermen, trykk og hold på skillelinjen"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Trykk og hold på handlingstasten for å søke etter det som er på skjermen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dette produktet bruker den merkede delen av skjermen til å søke. Dette er underlagt Googles <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>personvernregler<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> og <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>vilkår for bruk<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Trykk og hold på handlingstasten for å søke etter det som er på skjermen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dette produktet bruker den merkede delen av skjermen til å søke. Googles <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>personvernregler<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> og <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>vilkår for bruk<xliff:g id="END_TOS_LINK"></a></xliff:g> gjelder."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Lukk"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Ferdig"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Hjem"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Legg til apper på datamaskin"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Avbryt"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index f6668c1..38df28b 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार प्रयोग गरेर अझ धेरै कार्य गर्नुहोस्"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार सधैँ देखाउनुहोस्"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"आफ्नो स्क्रिनको पुछारमा टास्कबार सधैँ देखाइराख्न डिभाइडर टच एन्ड होल्ड गर्नुहोस्"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"आफ्नो स्क्रिनमा भएका कुराहरू खोज्न एक्सन कीमा टच एण्ड होल्ड गर्नुहोस्"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"यो उत्पादनले तपाईंले चयन गर्नुभएको स्क्रिनको भाग प्रयोग गरेर खोजी गर्छ। Google को <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>गोपनीयता नीति<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> र <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>सेवाका सर्तहरू<xliff:g id="END_TOS_LINK"></a></xliff:g> लागू हुन्छन्।"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"आफ्नो स्क्रिनमा भएका कुराहरू खोज्न एक्सन कीमा टच एन्ड होल्ड गर्नुहोस्"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"यो उत्पादनले तपाईंले चयन गर्नुभएको स्क्रिनको भाग प्रयोग गरेर खोजी गर्छ। Google को <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>गोपनीयता नीति<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> र <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>सेवाका सर्तहरू<xliff:g id="END_TOS_LINK"></a></xliff:g> लागू हुन्छन्।"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"बन्द गर्नुहोस्"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"सम्पन्न भयो"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"डेस्कटपमा एप हालिँदै छ"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"रद्द गर्नुहोस्"</string>
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index ed0bd5b..401351f 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -25,6 +25,21 @@
<item name="android:windowBackground">@android:color/transparent</item>
</style>
+ <style name="TextAppearance.GestureTutorial.MainTitle.Home"
+ parent="TextAppearance.GestureTutorial.MainTitle">
+ <item name="android:textColor">?attr/onSurfaceHome</item>
+ </style>
+
+ <style name="TextAppearance.GestureTutorial.MainTitle.Back"
+ parent="TextAppearance.GestureTutorial.MainTitle">
+ <item name="android:textColor">?attr/onSurfaceBack</item>
+ </style>
+
+ <style name="TextAppearance.GestureTutorial.MainTitle.Overview"
+ parent="TextAppearance.GestureTutorial.MainTitle">
+ <item name="android:textColor">?attr/onSurfaceOverview</item>
+ </style>
+
<style name="TextAppearance.GestureTutorial.MenuButton.Home"
parent="TextAppearance.GestureTutorial.MenuButton">
<item name="android:textColor">?attr/onSurfaceHome</item>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index c288868..fc435f8 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vrije vorm"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Doe meer met de taakbalk"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"De taakbalk altijd tonen"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Houd de scheidingslijn ingedrukt als je de taakbalk altijd onderaan je scherm wilt tonen"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Houd je vinger op de actietoets om te zoeken naar wat er op je scherm staat"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dit product gebruikt het geselecteerde gedeelte van je scherm om te zoeken. Het <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacybeleid<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> en de <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Servicevoorwaarden<xliff:g id="END_TOS_LINK"></a></xliff:g> van Google zijn van toepassing."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Houd je vinger op de actietoets om te zoeken naar wat er op je scherm staat"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Dit product gebruikt het geselecteerde gedeelte van je scherm om te zoeken. Het <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Privacybeleid<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> en de <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Servicevoorwaarden<xliff:g id="END_TOS_LINK"></a></xliff:g> van Google zijn van toepassing."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Sluiten"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"App toevoegen aan desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuleren"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index a7c5d44..2069e30 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ପିନ୍"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ଫ୍ରିଫର୍ମ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ଡେସ୍କଟପ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ବର୍ତ୍ତମାନର କୌଣସି ଆଇଟମ ନାହିଁ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ଆପ ବ୍ୟବହାର ସେଟିଂସ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ଟାସ୍କବାର ମାଧ୍ୟମରେ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ସର୍ବଦା ଟାସ୍କବାର ଦେଖାନ୍ତୁ"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ଆପଣଙ୍କ ସ୍କ୍ରିନର ନିମ୍ନରେ ସର୍ବଦା ଟାସ୍କବାର ଦେଖାଇବା ପାଇଁ ଡିଭାଇଡରକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ କଣ ଅଛି ତାହା ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଆକ୍ସନ କୀ\'କୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଏହି ପ୍ରଡକ୍ଟ ଆପଣଙ୍କ ସ୍କ୍ରିନର ଚୟନିତ ଅଂଶକୁ ବ୍ୟବହାର କରେ। Googleର <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ଗୋପନୀୟତା ନୀତି<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ଏବଂ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ସେବାର ସର୍ତ୍ତାବଳୀ<xliff:g id="END_TOS_LINK"></a></xliff:g> ଲାଗୁ ହୁଏ।"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ କଣ ଅଛି ତାହା ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଆକ୍ସନ କୀ\'କୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଏହି ପ୍ରଡକ୍ଟ ଆପଣଙ୍କ ସ୍କ୍ରିନର ଚୟନିତ ଅଂଶକୁ ବ୍ୟବହାର କରେ। Googleର <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ଗୋପନୀୟତା ନୀତି<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ଏବଂ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ସେବାର ସର୍ତ୍ତାବଳୀ<xliff:g id="END_TOS_LINK"></a></xliff:g> ଲାଗୁ ହୁଏ।"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ହୋଇଗଲା"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ହୋମ"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ଡେସ୍କଟପରେ ଆପ ଯୋଗ କରାଯାଉଛି"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ବାତିଲ କରନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 5c85461..58544a8 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ਫ੍ਰੀਫਾਰਮ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ਡੈਸਕਟਾਪ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮ ਨਹੀਂ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ਟਾਸਕਬਾਰ ਦਾ ਹੋਰ ਲਾਹਾ ਲਓ"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਉਣਾ"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ, ਵਿਭਾਜਕ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਮੌਜੂਦ ਸਮੱਗਰੀ ਨੂੰ ਖੋਜਣ ਲਈ, ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ਇਹ ਉਤਪਾਦ ਖੋਜ ਕਰਨ ਲਈ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਚੁਣੇ ਹੋਏ ਹਿੱਸੇ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। Google ਦੀ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ਪਰਦੇਦਾਰੀ ਨੀਤੀ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ਅਤੇ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ਸੇਵਾ ਦੇ ਨਿਯਮ<xliff:g id="END_TOS_LINK"></a></xliff:g> ਲਾਗੂ ਹੁੰਦੇ ਹਨ।"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਮੌਜੂਦ ਸਮੱਗਰੀ ਨੂੰ ਖੋਜਣ ਲਈ, ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ਇਹ ਉਤਪਾਦ ਖੋਜ ਕਰਨ ਲਈ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਚੁਣੇ ਹੋਏ ਹਿੱਸੇ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। Google ਦੀ <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>ਪਰਦੇਦਾਰੀ ਨੀਤੀ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ਅਤੇ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ਸੇਵਾ ਦੇ ਨਿਯਮ<xliff:g id="END_TOS_LINK"></a></xliff:g> ਲਾਗੂ ਹੁੰਦੇ ਹਨ।"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ਬੰਦ ਕਰੋ"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ਸਮਝ ਲਿਆ"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ਘਰ"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ਐਪ ਨੂੰ ਡੈਸਕਟਾਪ \'ਤੇ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ਰੱਦ ਕਰੋ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 11f46bc..0f55f11 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -90,7 +90,7 @@
<string name="allset_title" msgid="5021126669778966707">"Wszystko gotowe"</string>
<string name="allset_hint" msgid="459504134589971527">"Aby przejść na stronę główną, przesuń w górę"</string>
<string name="allset_button_hint" msgid="2395219947744706291">"Kliknij przycisk ekranu głównego, aby otworzyć ekran główny"</string>
- <string name="allset_description_generic" msgid="5385500062202019855">"Teraz możesz zacząć używać urządzenia <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+ <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> jest gotowe – możesz zacząć z niego korzystać"</string>
<string name="default_device_name" msgid="6660656727127422487">"urządzenie"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ustawienia nawigacji w systemie"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Udostępnij"</string>
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Wykorzystaj potencjał paska aplikacji"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Zawsze wyświetlaj pasek aplikacji"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Aby zawsze wyświetlać pasek aplikacji u dołu ekranu, naciśnij i przytrzymaj linię dzielenia ekranu"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Aby rozpocząć wyszukiwanie na podstawie zawartości ekranu, naciśnij i przytrzymaj klawisz działania"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Usługa przy wyszukiwaniu używa zaznaczonego fragmentu ekranu. Obowiązują zapisy <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Polityki prywatności<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Warunków korzystania z usług<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Aby rozpocząć wyszukiwanie na podstawie zawartości ekranu, naciśnij i przytrzymaj klawisz działania"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Usługa przy wyszukiwaniu używa zaznaczonego fragmentu ekranu. Obowiązują zapisy <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Polityki prywatności<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Warunków korzystania z usług<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Zamknij"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Gotowe"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Ekran główny"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodaję aplikację do komputera"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Anuluj"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 5af1bf6..761329a 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Faça mais com a Barra de tarefas"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostre sempre a Barra de tarefas"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar sempre a Barra de tarefas no fundo do ecrã, toque sem soltar no divisor"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Toque sem soltar na tecla de ação para pesquisar o que está no ecrã"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Este produto usa a parte selecionada do ecrã para pesquisar. Aplicam-se a <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> e os <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termos de Utilização<xliff:g id="END_TOS_LINK"></a></xliff:g> da Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Toque sem soltar na tecla de ação para pesquisar o que está no ecrã"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este produto usa a parte selecionada do ecrã para pesquisar. Aplicam-se a <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> e os <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termos de Utilização<xliff:g id="END_TOS_LINK"></a></xliff:g> da Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Concluir"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Início"</string>
@@ -138,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"A adicionar a app ao computador"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 9ea746c..a105087 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Aproveite ainda mais a Barra de tarefas"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Sempre mostrar a Barra de tarefas"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Toque e pressione o divisor para sempre mostrar a Barra de tarefas na parte de baixo da tela"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Toque e pressione a tecla de ação para pesquisar o que está na tela"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"O produto usa a parte selecionada da tela para pesquisar. O uso desses dados está sujeito à <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> e aos <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termos de Serviço<xliff:g id="END_TOS_LINK"></a></xliff:g> do Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Toque na tecla de ação e pressione para pesquisar o que está na tela"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"O produto usa a parte selecionada da tela para pesquisar. O uso desses dados está sujeito à <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> e aos <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termos de Serviço<xliff:g id="END_TOS_LINK"></a></xliff:g> do Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Concluído"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Início"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Adicionando app ao computador"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Cancelar"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index e45e45a..d5ab773 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixează"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formă liberă"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Fă mai multe din Bara de activități"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Afișează întotdeauna Bara de activități"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pentru a afișa mereu Bara de activități în partea de jos a ecranului, atinge lung separatorul"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Atinge lung tasta de acțiuni ca să cauți pe ecran"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Acest produs folosește partea selectată a ecranului pentru a căuta. Se aplică <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Politica de confidențialitate<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> și <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termenii și condițiile<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Atinge lung tasta de acțiuni ca să cauți pe ecran"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Acest produs folosește partea selectată a ecranului pentru a căuta. Se aplică <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Politica de confidențialitate<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> și <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Termenii și condițiile<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Închide"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Gata"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Ecran de pornire"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Se adaugă aplicația pe computer"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Anulează"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 6f1d9e7..c03d847 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закрепить"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Произвольная форма"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Включить режим для ПК"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Используйте все возможности панели задач"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Закрепите панель задач внизу экрана"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Для этого нажмите на разделитель и удерживайте его."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Чтобы найти информацию об объекте на экране, нажмите и удерживайте клавишу действия"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Этот продукт использует выделенную часть экрана для поиска. При этом действуют <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Политика конфиденциальности<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Условия использования<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Чтобы найти информацию об объекте на экране, нажмите и удерживайте клавишу действия"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Этот продукт использует выделенную часть экрана для поиска. При этом действуют <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Политика конфиденциальности<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Условия использования<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Закрыть"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Главный экран"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Добавление приложения на компьютер"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Отмена"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 3b7598b..7b3fd6d 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"කාර්ය තීරුව සමග තවත් කරන්න"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"සෑම විටම කාර්ය තීරුව පෙන්වන්න"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"සෑම විටම ඔබේ තිරයේ පතුලේ ඇති කාර්ය තීරුව පෙන්වීමට, බෙදුම්කරු ස්පර්ශ කර අල්ලාගෙන සිටින්න"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ඔබේ තිරයෙහි ඇති දේ සෙවීමට ක්රියා යතුර ස්පර්ශ කර සිටින්න"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"මෙම නිෂ්පාදනය සෙවීමට ඔබේ තිරයෙහි තෝරන ලද කොටස භාවිතා කරයි. Google හි <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>පෞද්ගලිකත්ව ප්රතිපත්තිය<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> සහ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>සේවා නියමයන්<xliff:g id="END_TOS_LINK"></a></xliff:g> අදාළ වේ."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"ඔබේ තිරයෙහි ඇති දේ සෙවීමට ක්රියා යතුර ස්පර්ශ කර සිටින්න"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"මෙම නිෂ්පාදනය සෙවීමට ඔබේ තිරයෙහි තෝරන ලද කොටස භාවිතා කරයි. Google හි <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>පෞද්ගලිකත්ව ප්රතිපත්තිය<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> සහ <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>සේවා නියමයන්<xliff:g id="END_TOS_LINK"></a></xliff:g> අදාළ වේ."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"වසන්න"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"නිමයි"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"මුල් පිටුව"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ඩෙස්ක්ටොප් වෙත යෙදුම එක් කිරීම"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"අවලංගු කරන්න"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 48f7a9c..1737f07 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Panel aplikácií vám ponúka ďalšie možnosti"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vždy zobrazovať panel aplikácií"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ak chcete, aby sa panel aplikácií vždy zobrazoval v dolnej časti obrazovky, pridržte rozdeľovač"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ak chcete vyhľadávať, čo je na obrazovke, pridržte akčný kláves."</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Táto služba používa na účely vyhľadávania vybranú časť obrazovky. Uplatňujú sa <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>pravidlá ochrany súkromia<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> a <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>zmluvné podmienky<xliff:g id="END_TOS_LINK"></a></xliff:g> spoločnosti Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ak chcete vyhľadávať, čo je na obrazovke, pridržte akčný kláves"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Táto služba používa na účely vyhľadávania vybranú časť obrazovky. Uplatňujú sa <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>pravidlá ochrany súkromia<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> a <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>zmluvné podmienky<xliff:g id="END_TOS_LINK"></a></xliff:g> spoločnosti Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Zavrieť"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Plocha"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Pridanie aplikácie na plochu"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Zrušiť"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 58e34f2..da290fc 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Prosta oblika"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Namizni računalnik"</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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Naredite več z opravilno vrstico"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stalni prikaz opravilne vrstice"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Če želite, da je opravilna vrstica vedno prikazana na dnu zaslona, pridržite razdelilno črto."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Za iskanje po zaslonu se dotaknite in pridržite tipko za dejanja"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ta izdelek za iskanje uporablja izbrani del zaslona. Veljajo Googlov <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>pravilnik o zasebnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> in <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>pogoji storitve<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Za iskanje po zaslonu se dotaknite in pridržite tipko za dejanja"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ta izdelek za iskanje uporablja izbrani del zaslona. Veljajo Googlov <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>pravilnik o zasebnosti<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> in <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>pogoji storitve<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Zapri"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Končano"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Začetni zaslon"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Dodajanje aplikacije na namizje"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Prekliči"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 7ae201f..1b2db75 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formë e lirë"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Bëj më shumë me \"Shiritin e detyrave\""</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Shfaq gjithmonë \"Shiritin e detyrave\""</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Prek e mbaj ndarësin dhe shfaq gjithmonë \"Shiritin e detyrave\" në fund të ekranit"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Prek dhe mbaj shtypur tastin e veprimit për të kërkuar për gjërat në ekran"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ky produkt përdor pjesën e zgjedhur të ekranit tënd për të kërkuar. Zbatohen <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Politika e privatësisë<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> dhe <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Kushtet e shërbimit<xliff:g id="END_TOS_LINK"></a></xliff:g> të Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Prek dhe mbaj shtypur tastin e veprimit për të kërkuar për gjërat në ekran"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ky produkt përdor pjesën e zgjedhur të ekranit tënd për të kërkuar. Zbatohen <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Politika e privatësisë<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> dhe <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Kushtet e shërbimit<xliff:g id="END_TOS_LINK"></a></xliff:g> të Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Mbyll"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"U krye"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Faqja kryesore"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Shtimi i aplikacionit te desktopi"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Anulo"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 2a7239e..56e2c91 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Урадите више помоћу траке задатака"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Увек приказуј траку задатака"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Да би трака задатака увек била приказана у дну екрана, додирните и задржите разделник"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Додирните и задржите тастер радњи да бисте претражили оно што је на екрану"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Овај производ користи изабрани део екрана за претрагу. Примењују се Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>политика приватности<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>услови коришћења услуге<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Додирните и задржите тастер радњи да бисте претражили оно што је на екрану"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Овај производ користи изабрани део екрана за претрагу. Примењују се Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>политика приватности<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> и <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>услови коришћења услуге<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Почетна"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Додаје се апликација на радну поврршину"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Откажи"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 808cfe9..cec75d9 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -96,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Systemnavigeringsinställningar"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Dela"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
- <string name="action_split" msgid="2098009717623550676">"Delat"</string>
+ <string name="action_split" msgid="2098009717623550676">"Delad skärm"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"Spara app-par"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Välj en annan app för att använda delad skärm"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Gör mer med aktivitetsfältet"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Visa alltid aktivitetsfältet"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Tryck länge på avgränsaren för att alltid visa aktivitetsfältet längst ned på skärmen"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Tryck länge på åtgärdstangenten för att söka efter det som finns på skärmen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Den här produkten använder den valda delen av skärmen för att söka. Googles <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>integritetspolicy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> och <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>användarvillkor<xliff:g id="END_TOS_LINK"></a></xliff:g> gäller."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Tryck länge på åtgärdstangenten för att söka efter det som finns på skärmen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Den här produkten använder den valda delen av skärmen för att söka. Googles <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>integritetspolicy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> och <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>användarvillkor<xliff:g id="END_TOS_LINK"></a></xliff:g> gäller."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Stäng"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Klar"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Startsida"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Lägger till appen på skrivbordet"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Avbryt"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index ba960ec..329f332 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Kamilisha mengi kwa kutumia Upauzana huu"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Onyesha Upauzana kila wakati"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ili uonyeshe Upauzana kila wakati chini ya skrini yako, gusa na ushikilie kitenganishi"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Gusa na ushikilie kitufe cha vitendo ili utafute kilicho kwenye skrini yako"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bidhaa hii hutumia sehemu uliyochagua kwenye skrini yako kutafuta. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Sera ya Faragha<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> na <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Sheria na Masharti<xliff:g id="END_TOS_LINK"></a></xliff:g> ya Google yatatumika."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Gusa na ushikilie kitufe cha vitendo ili utafute kilicho kwenye skrini yako"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bidhaa hii hutumia sehemu uliyochagua kwenye skrini yako kutafuta. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Sera ya Faragha<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> na <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Sheria na Masharti<xliff:g id="END_TOS_LINK"></a></xliff:g> ya Google yatatumika."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Funga"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Imemaliza"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Mwanzo"</string>
@@ -138,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Kuweka programu kwenye Eneo-kazi"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Ghairi"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index c5cbfcd..4598925 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"குறிப்பிட்ட வடிவமில்லாத பயன்முறை"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"டெஸ்க்டாப்"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ஆப்ஸ் உபயோக அமைப்புகள்"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"எல்லாம் அழி"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"செயல் பட்டி மூலம் மேலும் பலவற்றைச் செய்யுங்கள்"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"செயல் பட்டியை எப்போதும் காட்டுதல்"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"திரையின் கீழ்ப்பகுதியில் செயல் பட்டியை எப்போதும் காட்டுவதற்கு, பிரிப்பானைத் தொட்டுப் பிடித்திருக்கவும்"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"உங்கள் திரையில் உள்ளவற்றைத் தேடுவதற்கு ஆக்ஷன் பட்டனைத் தொட்டுப் பிடியுங்கள்"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"தேடுவதற்கு உங்கள் திரையின் தேர்ந்தெடுக்கப்பட்ட பகுதியை இந்தத் தயாரிப்பு பயன்படுத்துகிறது. Googleளின் <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>தனியுரிமைக் கொள்கையும்<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>சேவை விதிமுறைகளும்<xliff:g id="END_TOS_LINK"></a></xliff:g> பொருந்தும்."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"உங்கள் திரையில் உள்ளவற்றைத் தேடுவதற்கு ஆக்ஷன் பட்டனைத் தொட்டுப் பிடியுங்கள்"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"தேடுவதற்கு உங்கள் திரையின் தேர்ந்தெடுக்கப்பட்ட பகுதியை இந்தத் தயாரிப்பு பயன்படுத்துகிறது. Googleளின் <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>தனியுரிமைக் கொள்கையும்<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>சேவை விதிமுறைகளும்<xliff:g id="END_TOS_LINK"></a></xliff:g> பொருந்தும்."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"முடிந்தது"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"முகப்பு"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ஆப்ஸை டெஸ்க்டாப்பில் சேர்க்கிறது"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ரத்துசெய்"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index f2c06b4..49d2b9b 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"టాస్క్బార్తో మరిన్ని చేయండి"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"టాస్క్బార్ను నిరంతరం చూపండి"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"మీ స్క్రీన్ దిగువున టాస్క్బార్ను నిరంతరం చూపడానికి, డివైడర్ను తాకి, నొక్కి ఉంచండి"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"మీ స్క్రీన్లో ఏం ఉందో సెర్చ్ చేయడానికి యాక్షన్ కీని తాకి ఉంచండి"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ఈ ప్రోడక్ట్, సెర్చ్ చేయడానికి మీ స్క్రీన్లో ఎంచుకున్న భాగాన్ని ఉపయోగిస్తుంది. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>గోప్యతా పాలసీ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>, <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>సర్వీస్ నియమాలు<xliff:g id="END_TOS_LINK"></a></xliff:g> వర్తిస్తాయి."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"మీ స్క్రీన్లో ఏం ఉందో సెర్చ్ చేయడానికి యాక్షన్ కీని తాకి ఉంచండి"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ఈ ప్రోడక్ట్, సెర్చ్ చేయడానికి మీ స్క్రీన్లో ఎంచుకున్న భాగాన్ని ఉపయోగిస్తుంది. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>గోప్యతా పాలసీ<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>, <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>సర్వీస్ నియమాలు<xliff:g id="END_TOS_LINK"></a></xliff:g> వర్తిస్తాయి."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"మూసివేయండి"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"పూర్తయింది"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"మొదటి ట్యాబ్"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"డెస్క్టాప్నకు యాప్ను జోడిస్తోంది"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"రద్దు చేయండి"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index c5f0b3e..14a8741 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -92,7 +92,7 @@
<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>
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ทำสิ่งต่างๆ ได้มากขึ้นด้วยแถบงาน"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"แสดงแถบงานเสมอ"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"หากต้องการให้แถบงานแสดงที่ด้านล่างหน้าจออยู่เสมอ ให้แตะตัวแบ่งค้างไว้"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"แตะปุ่มดำเนินการค้างไว้เพื่อค้นหาสิ่งที่อยู่บนหน้าจอ"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ผลิตภัณฑ์นี้ใช้ส่วนที่เลือกของหน้าจอเพื่อค้นหา เป็นไปตาม<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>นโยบายความเป็นส่วนตัว<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>และ<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ข้อกําหนดในการให้บริการ<xliff:g id="END_TOS_LINK"></a></xliff:g>ของ Google"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"แตะปุ่มดำเนินการค้างไว้เพื่อค้นหาสิ่งที่อยู่บนหน้าจอ"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"ผลิตภัณฑ์นี้ใช้ส่วนที่เลือกของหน้าจอเพื่อค้นหา เป็นไปตาม<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>นโยบายความเป็นส่วนตัว<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>และ<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>ข้อกําหนดในการให้บริการ<xliff:g id="END_TOS_LINK"></a></xliff:g>ของ Google"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"ปิด"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"เสร็จ"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"หน้าแรก"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"การเพิ่มแอปไปยังเดสก์ท็อป"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"ยกเลิก"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 5fbc57b..d97706a 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Mas maraming magawa gamit ang Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Palaging ipakita ang Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para palaging ipakita ang Taskbar sa ibaba ng iyong screen, pindutin nang matagal ang divider"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Pindutin nang matagal ang action key para hanapin kung ano ang nasa iyong screen"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ginagamit ng produktong ito ang piniling bahagi ng iyong screen para maghanap. Nalalapat ang <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Patakaran sa Privacy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> at <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Mga Tuntunin ng Serbisyo<xliff:g id="END_TOS_LINK"></a></xliff:g> ng Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Pindutin nang matagal ang action key para hanapin kung ano ang nasa iyong screen"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Ginagamit ng produktong ito ang piniling bahagi ng iyong screen para maghanap. Nalalapat ang <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Patakaran sa Privacy<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> at <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Mga Tuntunin ng Serbisyo<xliff:g id="END_TOS_LINK"></a></xliff:g> ng Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Isara"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Tapos na"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Idinaragdag ang app sa Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Kanselahin"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 79f8ad1..1d73f8f 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Serbest çalışma"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Görev çubuğuyla daha fazla şey yapın"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Görev çubuğunu sabitleyin"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ayırıcıya dokunup basılı tuttuğunuzda görev çubuğu ekranın alt kısmına sabitlenir"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekranınızda bulunan içerikleri aramak için eylem tuşuna dokunup basılı tutun"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bu ürün, ekranınızın seçilen bölümünü kullanarak arama yapar. Google\'ın <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Gizlilik Politikası<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ve <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Hizmet Şartları<xliff:g id="END_TOS_LINK"></a></xliff:g> geçerlidir."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekranınızda bulunan içerikleri aramak için eylem tuşuna dokunup basılı tutun"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bu ürün, ekranınızın seçilen bölümünü kullanarak arama yapar. Google\'ın <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Gizlilik Politikası<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ve <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Hizmet Şartları<xliff:g id="END_TOS_LINK"></a></xliff:g> geçerlidir."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Kapat"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Bitti"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Ana ekran"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Uygulama Masaüstü\'ne ekleniyor"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"İptal"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index c1ef51d..2ad4437 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закріпити"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Довільна форма"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Комп’ютер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налаштування використання додатка"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистити все"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Більше можливостей завдяки панелі завдань"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Завжди показувати панель завдань"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Щоб завжди показувати панель завдань унизу екрана, натисніть і втримуйте роздільник"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Для пошуку інформації, що відображається на екрані, натисніть і втримуйте клавішу дії"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Цей продукт використовує для пошуку вибрану частину екрана. Застосовуються <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Політика конфіденційності<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> та <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Загальні положення й умови<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Для пошуку інформації, що відображається на екрані, натисніть і втримуйте клавішу дії"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Цей продукт використовує для пошуку вибрану частину екрана. Застосовуються <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Політика конфіденційності<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> та <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Загальні положення й умови<xliff:g id="END_TOS_LINK"></a></xliff:g> Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Головний екран"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"Встановлення додатка на комп’ютер"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Скасувати"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 7b14045..dbb226f6 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"فری فارم"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ڈیسک ٹاپ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ایپ کے استعمال کی ترتیبات"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"ٹاسک بار سے بہت کچھ کریں"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ہمیشہ ٹاسک بار دکھائیں"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ٹاسک بار کو ہمیشہ اپنی اسکرین کے نیچے دکھانے کے لیے، ڈیوائیڈر کو ٹچ کریں اور دبائے رکھیں"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"آپ کی اسکرین پر جو کچھ ہے اسے تلاش کرنے کے لیے ایکشن کلید کو ٹچ کریں اور دبائے رکھیں"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"یہ پروڈکٹ تلاش کرنے کے لیے آپ کی اسکرین کا منتخب حصہ استعمال کرتا ہے۔ Google کی <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>رازداری کی پالیسی<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> اور <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>سروس کی شرائط<xliff:g id="END_TOS_LINK"></a></xliff:g> لاگو ہوتی ہیں۔"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"آپ کی اسکرین پر جو کچھ ہے اسے تلاش کرنے کے لیے ایکشن کلید کو ٹچ کریں اور دبائے رکھیں"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"یہ پروڈکٹ تلاش کرنے کے لیے آپ کی اسکرین کا منتخب حصہ استعمال کرتا ہے۔ Google کی <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>رازداری کی پالیسی<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> اور <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>سروس کی شرائط<xliff:g id="END_TOS_LINK"></a></xliff:g> لاگو ہوتی ہیں۔"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"بند کریں"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"ہو گیا"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"ہوم"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"ڈیسک ٹاپ پر ایپ شامل کرنا"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"منسوخ کریں"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index e543225..75ac23e 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Qadash"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Vazifalar panelidan maksimal darajada foydalaning"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vazifalar paneli doim chiqarilsin"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Vazifalar panelini ekranning pastki qismida doim chiqib turishi uchun ajratkichni bosib turing"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekrandagi element haqida maʼlumotni topish uchun amal tugmasini bosib turing"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bu mahsulot qidirish uchun ekranning tanlangan qismidan foydalanadi. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>maxfiylik siyosati<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> va <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>xizmat shartlari<xliff:g id="END_TOS_LINK"></a></xliff:g> tatbiq qilinadi."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Ekrandagi element haqida maʼlumotni topish uchun amal tugmasini bosib turing"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Bu mahsulot qidirish uchun ekranning tanlangan qismidan foydalanadi. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>maxfiylik siyosati<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> va <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>xizmat shartlari<xliff:g id="END_TOS_LINK"></a></xliff:g> tatbiq qilinadi."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Yopish"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Tayyor"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Bosh ekran"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Ilova kompyuterga qoʻshilmoqda"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Bekor qilish"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 136e1d2..55b7585 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Dạng tự do"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -93,7 +92,7 @@
<string name="allset_button_hint" msgid="2395219947744706291">"Nhấn vào nút màn hình chính để chuyển đến màn hình chính"</string>
<string name="allset_description_generic" msgid="5385500062202019855">"Bạn có thể bắt đầu sử dụng <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="default_device_name" msgid="6660656727127422487">"thiết bị"</string>
- <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Chế độ cài đặt di chuyển trên hệ thống"</annotation></string>
+ <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Cài đặt cách thao tác trên hệ thống"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
<string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Làm nhiều việc hơn qua Thanh tác vụ"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Luôn hiện Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Để luôn hiện Taskbar ở cuối màn hình, hãy nhấn và giữ đường phân chia"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Hãy chạm và giữ phím hành động để tìm xem trên màn hình của bạn có gì"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Sản phẩm này dùng phần được chọn trên màn hình để tìm kiếm. Có áp dụng <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Chính sách quyền riêng tư<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> và <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Điều khoản dịch vụ<xliff:g id="END_TOS_LINK"></a></xliff:g> của Google."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Chạm và giữ phím hành động để tìm nội dung trên màn hình của bạn"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Sản phẩm này dùng phần được chọn trên màn hình để tìm kiếm. Có áp dụng <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Chính sách quyền riêng tư<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> và <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Điều khoản dịch vụ<xliff:g id="END_TOS_LINK"></a></xliff:g> của Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Đóng"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Xong"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Màn hình chính"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Đang thêm ứng dụng vào máy tính"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Huỷ"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b90d6bf..727f3e7 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由窗口"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面设备"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"应用使用设置"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -96,7 +95,7 @@
<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_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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"体验任务栏的更多功能"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"始终显示任务栏"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"若要始终在屏幕底部显示任务栏,请轻触并按住分隔线"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"轻触并按住操作键,即可根据屏幕上的内容进行搜索"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"此产品会根据您在屏幕上选取的部分进行搜索。Google 的<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>《隐私权政策》<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>和<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>《服务条款》<xliff:g id="END_TOS_LINK"></a></xliff:g>在此适用。"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"轻触并按住操作键,即可根据屏幕上的内容进行搜索"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"此产品会根据屏幕上的所选内容进行搜索。Google 的<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>《隐私权政策》<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>和<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>《服务条款》<xliff:g id="END_TOS_LINK"></a></xliff:g>适用。"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"关闭"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"主屏幕"</string>
@@ -139,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"将应用添加到桌面"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 45cf781..519a7b2 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
- <string name="recent_task_option_desktop" msgid="8280879717125435668">"電腦"</string>
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"工作列助你事半功倍"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"一律顯示工作列"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"如要持續在畫面底部顯示工作列,請按住分隔線"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"此產品使用螢幕的特定部分進行搜尋。須受 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>私隱權政策<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>服務條款<xliff:g id="END_TOS_LINK"></a></xliff:g>》約束。"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"此產品使用螢幕的特定部分進行搜尋。須受 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>私隱權政策<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>服務條款<xliff:g id="END_TOS_LINK"></a></xliff:g>》約束。"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"住宅"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"正在新增應用程式至桌面"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index ef811c4..a8cefce 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -117,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"充分發揮工作列的功用"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"一律顯示工作列"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"如要一律在畫面底部顯示工作列,請按住分隔線"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"這項產品會搜尋你在畫面上選取的內容 (適用 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>隱私權政策<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>服務條款<xliff:g id="END_TOS_LINK"></a></xliff:g>》)。"</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"這項產品會搜尋你在畫面上選取的內容 (適用 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>隱私權政策<xliff:g id="END_PRIVACY_LINK"></a></xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>服務條款<xliff:g id="END_TOS_LINK"></a></xliff:g>》)。"</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"主畫面"</string>
@@ -138,6 +138,7 @@
<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_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
<string name="desktop_select_app_toast" msgid="2306057322833956910">"新增應用程式至桌面"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 5723214..9028210 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
@@ -118,8 +117,8 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Yenza okwengeziwe nge-Taskbar"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Bonisa njalo i-Taskbar"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ukuze ubonise njalo i-Taskbar phansi kwesikrini sakho, thinta bese ubamba isihlukanisi"</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Thinta uphinde ubambe inkinobho yokufinyelela ukuze useshe lokho okukusikrini sakho"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Lo mkhiqizo usebenzisa ingxenye ekhethiwe yesikrini sakho ukusesha. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Inqubomgomo Yobumfihlo<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ye-Google kanye <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Nemigomo Yesevisi<xliff:g id="END_TOS_LINK"></a></xliff:g> iyasebenza."</string>
+ <string name="taskbar_search_edu_title" msgid="5569194922234364530">"Thinta uphinde ubambe inkinobho yokufinyelela ukuze useshe lokho okusesikrinini sakho"</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Lo mkhiqizo usebenzisa ingxenye ekhethiwe yesikrini sakho ukusesha. <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Inqubomgomo Yobumfihlo<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> ye-Google kanye <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Nemigomo Yesevisi<xliff:g id="END_TOS_LINK"></a></xliff:g> ziyasebenza."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Vala"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Kwenziwe"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Ikhaya"</string>
@@ -139,6 +138,7 @@
<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_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="desktop_select_app_toast" msgid="2306057322833956910">"Yengeza i-app ku-Deskithophu"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Khansela"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 1b5b0ee..14a916f 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -31,6 +31,7 @@
<color name="taskbar_nav_icon_dark_color_on_home">#99000000</color>
<color name="taskbar_stashed_handle_light_color">#EBffffff</color>
<color name="taskbar_stashed_handle_dark_color">#99000000</color>
+ <color name="taskbar_running_app_indicator_color">#646464</color>
<!-- Floating rotation button -->
<color name="floating_rotation_button_light_color">#ffffff</color>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 28cdb99..fd12210 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -17,8 +17,7 @@
<string name="overscroll_plugin_factory_class" translatable="false" />
<string name="task_overlay_factory_class" translatable="false"/>
- <!-- Activities which block home gesture -->
- <string-array name="gesture_blocking_activities" translatable="false">
+ <string-array name="back_gesture_blocking_activities" translatable="false">
<item>com.android.launcher3/com.android.quickstep.interaction.GestureSandboxActivity</item>
</string-array>
@@ -35,6 +34,7 @@
<string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
<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="nav_handle_long_press_handler_class" translatable="false"></string>
<string name="assist_utils_class" translatable="false"></string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index dc28614..7f09b6e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -177,6 +177,8 @@
<dimen name="gesture_tutorial_menu_done_button_top_spacing">0dp</dimen>
<dimen name="gesture_tutorial_menu_back_shape_bottom_margin">0dp</dimen>
<dimen name="gesture_tutorial_menu_done_button_spacing">72dp</dimen>
+ <dimen name="gesture_tutorial_done_button_bottom_margin">40dp</dimen>
+ <dimen name="gesture_tutorial_done_button_end_margin">24dp</dimen>
<!-- Gesture Tutorial mock conversations -->
<dimen name="gesture_tutorial_message_icon_size">44dp</dimen>
@@ -353,6 +355,9 @@
<dimen name="taskbar_back_button_suw_start_margin">48dp</dimen>
<dimen name="taskbar_back_button_suw_bottom_margin">1dp</dimen>
<dimen name="taskbar_back_button_suw_height">72dp</dimen>
+ <dimen name="taskbar_running_app_indicator_height">4dp</dimen>
+ <dimen name="taskbar_running_app_indicator_width">14dp</dimen>
+ <dimen name="taskbar_running_app_indicator_top_margin">2dp</dimen>
<!-- Transient taskbar -->
<dimen name="transient_taskbar_padding">12dp</dimen>
@@ -403,7 +408,7 @@
<dimen name="taskbar_edu_features_tooltip_width_with_one_feature">412dp</dimen>
<dimen name="taskbar_edu_features_tooltip_width_with_two_features">428dp</dimen>
<dimen name="taskbar_edu_features_tooltip_width_with_three_features">624dp</dimen>
- <dimen name="taskbar_edu_circle_to_search_subtitle_text_size">12sp</dimen>
+ <dimen name="taskbar_edu_search_subtitle_text_size">12sp</dimen>
<!--- Taskbar Pinning -->
<dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
@@ -420,7 +425,12 @@
<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_pointer_size">8dp</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>
+ <dimen name="bubblebar_pointer_width">12dp</dimen>
+ <dimen name="bubblebar_pointer_height">10dp</dimen>
+ <dimen name="bubblebar_pointer_radius">2dp</dimen>
<!-- Container size with pointer included: bubblebar_size + bubblebar_pointer_size -->
<dimen name="bubblebar_size_with_pointer">80dp</dimen>
<dimen name="bubblebar_elevation">1dp</dimen>
@@ -448,6 +458,11 @@
<!-- Bubble bar drop target -->
<dimen name="bubblebar_drop_target_corner_radius">36dp</dimen>
+ <dimen name="bubble_expanded_view_drop_target_default_width">412dp</dimen>
+ <dimen name="bubble_expanded_view_drop_target_default_height">600dp</dimen>
+ <dimen name="bubble_expanded_view_drop_target_corner_radius">28dp</dimen>
+ <dimen name="bubble_expanded_view_drop_target_padding">24dp</dimen>
+ <dimen name="bubble_expanded_view_drop_target_margin">16dp</dimen>
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index fc3c0e3..278c66a 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -275,10 +275,10 @@
<string name="taskbar_edu_pinning_title">Always show the Taskbar</string>
<!-- Text in dialog that shows a user how to pin the Taskbar. [CHAR_LIMIT 150] -->
<string name="taskbar_edu_pinning_standalone">To always show the Taskbar on the bottom of your screen, touch & hold the divider</string>
- <!-- Title in dialog that shows a user how to invoke the Circle to Search feature. [CHAR_LIMIT 150] -->
- <string name="taskbar_edu_circle_to_search_title">Touch & hold the action key to search what\'s on your screen</string>
+ <!-- Title in dialog that shows a user how to invoke the Search feature. [CHAR_LIMIT 150] -->
+ <string name="taskbar_search_edu_title">Touch & hold the action key to search what\'s on your screen</string>
<!-- Message showed to user to disclose privacy information they need to accept in order to access the app. [CHAR LIMIT=200]-->
- <string name="taskbar_edu_circle_to_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link"><a href=\"%1$s\"></xliff:g>Privacy Policy<xliff:g id="end_privacy_link"></a></xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link"><a href=\"%2$s\"></xliff:g>Terms of Service<xliff:g id="end_tos_link"></a></xliff:g> apply.</string>
+ <string name="taskbar_edu_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link"><a href=\"%1$s\"></xliff:g>Privacy Policy<xliff:g id="end_privacy_link"></a></xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link"><a href=\"%2$s\"></xliff:g>Terms of Service<xliff:g id="end_tos_link"></a></xliff:g> apply.</string>
<!-- Text on button to exit a tutorial [CHAR_LIMIT=16] -->
<string name="taskbar_edu_close">Close</string>
<!-- Text on button to finish a tutorial [CHAR_LIMIT=16] -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 16fb6d2..952505a 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -169,17 +169,17 @@
<style name="TextAppearance.GestureTutorial.MainTitle.Home"
parent="TextAppearance.GestureTutorial.MainTitle">
- <item name="android:textColor">?attr/onSurfaceHome</item>
+ <item name="android:textColor">?attr/secondaryHome</item>
</style>
<style name="TextAppearance.GestureTutorial.MainTitle.Back"
parent="TextAppearance.GestureTutorial.MainTitle">
- <item name="android:textColor">?attr/onSurfaceBack</item>
+ <item name="android:textColor">?attr/secondaryBack</item>
</style>
<style name="TextAppearance.GestureTutorial.MainTitle.Overview"
parent="TextAppearance.GestureTutorial.MainTitle">
- <item name="android:textColor">?attr/onSurfaceOverview</item>
+ <item name="android:textColor">?attr/secondaryOverview</item>
</style>
<style name="TextAppearance.GestureTutorial.MainTitle.Success.Home"
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 0697f47..72aaa90 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -58,6 +58,7 @@
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;
import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
@@ -1881,7 +1882,7 @@
return new ContainerAnimationRunner(
new ActivityTransitionAnimator.AnimationDelegate(
- controller, callback, listener));
+ MAIN_EXECUTOR, controller, callback, listener));
}
/**
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 694475a..84c2ed2 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -28,14 +28,15 @@
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
+import android.view.accessibility.AccessibilityManager;
import androidx.annotation.ColorInt;
import androidx.core.content.ContextCompat;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
-import com.android.launcher3.util.Themes;
/**
* A view which shows a horizontal divider
@@ -54,6 +55,7 @@
private final @ColorInt int mStrokeColor;
private final @ColorInt int mAllAppsLabelTextColor;
+ private final AccessibilityManager mAccessibilityManager;
private Layout mAllAppsLabelLayout;
private boolean mShowAllAppsLabel;
@@ -87,7 +89,8 @@
mAllAppsLabelTextColor = ContextCompat.getColor(context,
R.color.material_color_on_surface_variant);
- mShowAllAppsLabel = !ALL_APPS_VISITED_COUNT.hasReachedMax(context);
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
+ setShowAllAppsLabel(!ALL_APPS_VISITED_COUNT.hasReachedMax(context));
}
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
@@ -99,6 +102,9 @@
/** {@code true} if all apps label should be shown in place of divider. */
public void setShowAllAppsLabel(boolean showAllAppsLabel) {
+ if (mAccessibilityManager.isEnabled() && !Utilities.isRunningInTestHarness()) {
+ showAllAppsLabel = true;
+ }
if (showAllAppsLabel != mShowAllAppsLabel) {
mShowAllAppsLabel = showAllAppsLabel;
updateDividerType();
@@ -148,6 +154,7 @@
mDividerType = dividerType;
int topPadding;
int bottomPadding;
+ setContentDescription(null);
switch (dividerType) {
case LINE:
topPadding = 0;
@@ -161,6 +168,7 @@
bottomPadding = getResources()
.getDimensionPixelSize(R.dimen.all_apps_label_bottom_padding);
mPaint.setColor(mAllAppsLabelTextColor);
+ setContentDescription(mAllAppsLabelLayout.getText());
break;
case NONE:
default:
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 70e01f5..a16031d 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -286,7 +286,7 @@
}
public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + this.getClass().getSimpleName());
+ writer.println(prefix + "PredictionRowView");
writer.println(prefix + "\tmPredictionsEnabled: " + mPredictionsEnabled);
writer.println(prefix + "\tmPredictionUiUpdatePaused: " + mPredictionUiUpdatePaused);
writer.println(prefix + "\tmNumPredictedAppsPerRow: " + mNumPredictedAppsPerRow);
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 1c5a75d..de974ec 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -29,6 +29,7 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.ComponentName;
+import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.ViewGroup;
@@ -80,6 +81,7 @@
SystemShortcut.Factory<QuickstepLauncher>, DeviceProfile.OnDeviceProfileChangeListener,
DragSource, ViewGroup.OnHierarchyChangeListener {
+ private static final String TAG = "HotseatPredictionController";
private static final int FLAG_UPDATE_PAUSED = 1 << 0;
private static final int FLAG_DRAG_IN_PROGRESS = 1 << 1;
private static final int FLAG_FILL_IN_PROGRESS = 1 << 2;
@@ -292,6 +294,16 @@
}
/**
+ * Ensures that if the flag FLAG_UPDATE_PAUSED is active we set it to false.
+ */
+ public void verifyUIUpdateNotPaused() {
+ if ((mPauseFlags & FLAG_UPDATE_PAUSED) != 0) {
+ setPauseUIUpdate(false);
+ Log.e(TAG, "FLAG_UPDATE_PAUSED should not be set to true (see b/339700174)");
+ }
+ }
+
+ /**
* Sets or updates the predicted items
*/
public void setPredictedItems(FixedContainerItems items) {
@@ -521,7 +533,7 @@
}
public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + this.getClass().getSimpleName());
+ writer.println(prefix + "HotseatPredictionController");
writer.println(prefix + "\tFlags: " + getStateString(mPauseFlags));
writer.println(prefix + "\tmHotSeatItemsCount: " + mHotSeatItemsCount);
writer.println(prefix + "\tmPredictedItems: " + mPredictedItems);
diff --git a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
index 2fcbe4e..d604742 100644
--- a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
@@ -15,8 +15,8 @@
*/
package com.android.launcher3.model;
-import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
import static com.android.launcher3.EncryptionType.ENCRYPTED;
+import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
@@ -32,6 +32,7 @@
import com.android.launcher3.ConstantItem;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
@@ -47,7 +48,7 @@
/**
* Task to update model as a result of predicted apps update
*/
-public class PredictionUpdateTask extends BaseModelUpdateTask {
+public class PredictionUpdateTask implements ModelUpdateTask {
public static final ConstantItem<Boolean> LAST_PREDICTION_ENABLED =
nonRestorableItem("last_prediction_enabled_state", true, ENCRYPTED);
@@ -61,8 +62,9 @@
}
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList apps) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
+ LauncherAppState app = taskController.getApp();
Context context = app.getContext();
// TODO: remove this
@@ -119,7 +121,7 @@
FixedContainerItems fci = new FixedContainerItems(mPredictorState.containerId, items);
dataModel.extraItems.put(fci.containerId, fci);
- bindExtraContainerItems(fci);
+ taskController.bindExtraContainerItems(fci);
usersForChangedShortcuts.forEach(
u -> dataModel.updateShortcutPinnedState(app.getContext(), u));
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index fb14f9e..8b5ed7c 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -73,6 +73,7 @@
import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PersistedItemArray;
import com.android.quickstep.logging.SettingsChangeLogger;
import com.android.quickstep.logging.StatsLogCompatManager;
@@ -150,7 +151,8 @@
// TODO: Implement caching and preloading
WorkspaceItemFactory factory =
- new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, numColumns, state.containerId);
+ new WorkspaceItemFactory(mApp, ums, mPmHelper, pinnedShortcuts, numColumns,
+ state.containerId);
FixedContainerItems fci = new FixedContainerItems(state.containerId,
state.storage.read(mApp.getContext(), factory, ums.allUsers::get));
if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
@@ -326,8 +328,12 @@
super.destroy();
mActive = false;
StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
- if (mIsPrimaryInstance) {
- mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+ if (mIsPrimaryInstance && mStatsManager != null) {
+ try {
+ mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to unregister snapshot logging callback with StatsManager", e);
+ }
}
destroyPredictors();
}
@@ -526,6 +532,7 @@
private final LauncherAppState mAppState;
private final UserManagerState mUMS;
+ private final PackageManagerHelper mPmHelper;
private final Map<ShortcutKey, ShortcutInfo> mPinnedShortcuts;
private final int mMaxCount;
private final int mContainer;
@@ -533,9 +540,11 @@
private int mReadCount = 0;
protected WorkspaceItemFactory(LauncherAppState appState, UserManagerState ums,
- Map<ShortcutKey, ShortcutInfo> pinnedShortcuts, int maxCount, int container) {
+ PackageManagerHelper pmHelper, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts,
+ int maxCount, int container) {
mAppState = appState;
mUMS = ums;
+ mPmHelper = pmHelper;
mPinnedShortcuts = pinnedShortcuts;
mMaxCount = maxCount;
mContainer = container;
@@ -559,6 +568,7 @@
lai,
UserCache.INSTANCE.get(mAppState.getContext()).getUserInfo(user),
ApiWrapper.INSTANCE.get(mAppState.getContext()),
+ mPmHelper,
mUMS.isUserQuiet(user));
info.container = mContainer;
mAppState.getIconCache().getTitleAndIcon(info, lai, false);
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index c345d6e..a7c9652 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -32,7 +32,6 @@
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
-import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -48,9 +47,10 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.RemoteActionShortcut;
import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.util.BgObjectWithLooper;
+import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.views.ActivityContext;
@@ -61,7 +61,7 @@
/**
* Data model for digital wellbeing status of apps.
*/
-public final class WellbeingModel extends BgObjectWithLooper {
+public final class WellbeingModel implements SafeCloseable {
private static final String TAG = "WellbeingModel";
private static final int[] RETRY_TIMES_MS = {5000, 15000, 30000};
private static final boolean DEBUG = false;
@@ -81,8 +81,12 @@
private final Context mContext;
private final String mWellbeingProviderPkg;
- private Handler mWorkerHandler;
- private ContentObserver mContentObserver;
+ private final Handler mWorkerHandler;
+ private final ContentObserver mContentObserver;
+ private final SimpleBroadcastReceiver mWellbeingAppChangeReceiver =
+ new SimpleBroadcastReceiver(t -> restartObserver());
+ private final SimpleBroadcastReceiver mAppAddRemoveReceiver =
+ new SimpleBroadcastReceiver(this::onAppPackageChanged);
private final Object mModelLock = new Object();
// Maps the action Id to the corresponding RemoteAction
@@ -94,16 +98,23 @@
private WellbeingModel(final Context context) {
mContext = context;
mWellbeingProviderPkg = mContext.getString(R.string.wellbeing_provider_pkg);
- initializeInBackground("WellbeingHandler");
+ mWorkerHandler = new Handler(TextUtils.isEmpty(mWellbeingProviderPkg)
+ ? Executors.UI_HELPER_EXECUTOR.getLooper()
+ : Executors.getPackageExecutor(mWellbeingProviderPkg).getLooper());
+
+ mContentObserver = new ContentObserver(mWorkerHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateAllPackages();
+ }
+ };
+ mWorkerHandler.post(this::initializeInBackground);
}
- @Override
- protected void onInitialized(Looper looper) {
- mWorkerHandler = new Handler(looper);
- mContentObserver = newContentObserver(mWorkerHandler, this::onWellbeingUriChanged);
+ private void initializeInBackground() {
if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
mContext.registerReceiver(
- new SimpleBroadcastReceiver(t -> restartObserver()),
+ mWellbeingAppChangeReceiver,
getPackageFilter(mWellbeingProviderPkg,
Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED,
Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_DATA_CLEARED,
@@ -113,17 +124,21 @@
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
- mContext.registerReceiver(new SimpleBroadcastReceiver(this::onAppPackageChanged),
- filter, null, mWorkerHandler);
+ mContext.registerReceiver(mAppAddRemoveReceiver, filter, null, mWorkerHandler);
restartObserver();
}
}
- @WorkerThread
- private void onWellbeingUriChanged(Uri uri) {
- Preconditions.assertNonUiThread();
- updateAllPackages();
+ @Override
+ public void close() {
+ if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
+ mWorkerHandler.post(() -> {
+ mWellbeingAppChangeReceiver.unregisterReceiverSafely(mContext);
+ mAppAddRemoveReceiver.unregisterReceiverSafely(mContext);
+ mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+ });
+ }
}
public void setInTest(boolean inTest) {
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index f4cbf17..39f2c00 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -24,7 +24,7 @@
import androidx.annotation.NonNull;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
import com.android.launcher3.model.data.ItemInfo;
@@ -41,7 +41,7 @@
import java.util.stream.Collectors;
/** Task to update model as a result of predicted widgets update */
-public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask {
+public final class WidgetsPredictionUpdateTask implements ModelUpdateTask {
private final PredictorState mPredictorState;
private final List<AppTarget> mTargets;
@@ -58,8 +58,8 @@
* workspace.
*/
@Override
- public void execute(@NonNull final LauncherAppState appState,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
Set<ComponentKey> widgetsInWorkspace = dataModel.appWidgets.stream().map(
widget -> new ComponentKey(widget.providerName, widget.user)).collect(
Collectors.toSet());
@@ -98,7 +98,7 @@
List<ItemInfo> items;
if (enableCategorizedWidgetSuggestions()) {
- Context context = appState.getContext();
+ Context context = taskController.getApp().getContext();
WidgetRecommendationCategoryProvider categoryProvider =
WidgetRecommendationCategoryProvider.newInstance(context);
items = servicePredictedItems.stream()
@@ -115,7 +115,7 @@
new FixedContainerItems(mPredictorState.containerId, items);
dataModel.extraItems.put(mPredictorState.containerId, fixedContainerItems);
- bindExtraContainerItems(fixedContainerItems);
+ taskController.bindExtraContainerItems(fixedContainerItems);
// Don't store widgets prediction to disk because it is not used frequently.
}
diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
index 184ea71..fe9ade9 100644
--- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
+++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
@@ -25,7 +25,7 @@
/** {@link SystemShortcut.Factory} implementation to create workspace split shortcuts */
public interface QuickstepSystemShortcut {
- String TAG = QuickstepSystemShortcut.class.getSimpleName();
+ String TAG = "QuickstepSystemShortcut";
static SystemShortcut.Factory<QuickstepLauncher> getSplitSelectShortcutByPosition(
SplitPositionOption position) {
diff --git a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
index 2b6f77f..c94edce 100644
--- a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
+++ b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt
@@ -45,7 +45,7 @@
) : SystemShortcut<T>(iconResId, labelResId, target, itemInfo, originalView) where
T : Context?,
T : ActivityContext? {
- private val TAG = SystemShortcut::class.java.simpleName
+ private val TAG = "SplitShortcut"
// Initiate splitscreen from the Home screen or Home All Apps
protected val splitSelectSource: SplitSelectSource?
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 882682d..747612d 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -182,7 +182,7 @@
}
public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + this.getClass().getSimpleName());
+ writer.println(prefix + "DepthController");
writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
writer.println(prefix + "\tmSurface=" + mSurface);
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 74376c8..9eabb55 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -32,11 +32,15 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
import com.android.quickstep.GestureState;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.DesktopAppSelectView;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Controls the visibility of the workspace and the resumed / paused state when desktop mode
* is enabled.
@@ -48,6 +52,7 @@
private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
"persist.wm.debug.desktop_stashing", false);
private final Launcher mLauncher;
+ private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
private int mVisibleDesktopTasksCount;
private boolean mInOverviewState;
@@ -127,6 +132,16 @@
return mVisibleDesktopTasksCount;
}
+ /** Registers a listener for Desktop Mode visibility updates. */
+ public void registerDesktopVisibilityListener(DesktopVisibilityListener listener) {
+ mDesktopVisibilityListeners.add(listener);
+ }
+
+ /** Removes a previously registered Desktop Mode visibility listener. */
+ public void unregisterDesktopVisibilityListener(DesktopVisibilityListener listener) {
+ mDesktopVisibilityListeners.remove(listener);
+ }
+
/**
* Sets the number of desktop windows that are visible and updates launcher visibility based on
* it.
@@ -140,7 +155,12 @@
if (visibleTasksCount != mVisibleDesktopTasksCount) {
final boolean wasVisible = mVisibleDesktopTasksCount > 0;
final boolean isVisible = visibleTasksCount > 0;
+ final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
mVisibleDesktopTasksCount = visibleTasksCount;
+ final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+ if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+ notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+ }
if (!enableDesktopWindowingWallpaperActivity() && wasVisible != isVisible) {
// TODO: b/333533253 - Remove after flag rollout
@@ -179,15 +199,22 @@
+ " currentValue=" + mInOverviewState);
}
if (overviewStateEnabled != mInOverviewState) {
+ final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
mInOverviewState = overviewStateEnabled;
+ final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+ if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+ notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+ }
+
if (enableDesktopWindowingWallpaperActivity()) {
return;
}
// TODO: b/333533253 - Clean up after flag rollout
+
if (mInOverviewState) {
setLauncherViewsVisibility(View.VISIBLE);
markLauncherResumed();
- } else if (areDesktopTasksVisible() && !mGestureInProgress) {
+ } else if (areDesktopTasksVisibleNow && !mGestureInProgress) {
// Switching out of overview state and gesture finished.
// If desktop tasks are still visible, hide launcher again.
setLauncherViewsVisibility(View.INVISIBLE);
@@ -196,6 +223,16 @@
}
}
+ private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible);
+ }
+ for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
+ listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
+ }
+ DisplayController.handleInfoChangeForDesktopMode(mLauncher);
+ }
+
/**
* TODO: b/333533253 - Remove after flag rollout
*/
@@ -359,4 +396,14 @@
mSelectAppToast.hide();
mSelectAppToast = null;
}
+
+ /** A listener for when the user enters/exits Desktop Mode. */
+ public interface DesktopVisibilityListener {
+ /**
+ * Callback for when the user enters or exits Desktop Mode
+ *
+ * @param visible whether Desktop Mode is now visible
+ */
+ void onDesktopVisibilityChanged(boolean visible);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
deleted file mode 100644
index 3635827..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_NOTIFICATIONS;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_QUICK_SETTINGS;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo.Config;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.R;
-import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
-
-/**
- * Controller for managing buttons and status icons in taskbar in a desktop environment.
- */
-public class DesktopNavbarButtonsViewController extends NavbarButtonsViewController {
-
- private final TaskbarActivityContext mContext;
- private final FrameLayout mNavButtonsView;
- private final ViewGroup mNavButtonContainer;
- private final ViewGroup mStartContextualContainer;
- private final View mAllAppsButton;
-
- private TaskbarControllers mControllers;
-
- public DesktopNavbarButtonsViewController(TaskbarActivityContext context,
- @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
- super(context, navigationBarPanelContext, navButtonsView);
- mContext = context;
- mNavButtonsView = navButtonsView;
- mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
- mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
- mAllAppsButton = LayoutInflater.from(context)
- .inflate(R.layout.taskbar_all_apps_button, mStartContextualContainer, false);
- mAllAppsButton.setOnClickListener(v -> mControllers.taskbarAllAppsController.toggle());
- }
-
- /**
- * Initializes the controller
- */
- @Override
- public void init(TaskbarControllers controllers) {
- mControllers = controllers;
- super.init(controllers);
- }
-
- @Override
- protected void setupController() {
- mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarHeight;
-
- // Quick settings and notifications buttons
- addButton(R.drawable.ic_sysbar_quick_settings, BUTTON_QUICK_SETTINGS,
- mNavButtonContainer, mControllers.navButtonController,
- R.id.quick_settings_button);
- addButton(R.drawable.ic_sysbar_notifications, BUTTON_NOTIFICATIONS,
- mNavButtonContainer, mControllers.navButtonController,
- R.id.notifications_button);
- // All apps button
- mStartContextualContainer.addView(mAllAppsButton);
- }
-
- /** Cleans up on destroy */
- @Override
- public void onDestroy() { }
-
- @Override
- public void onConfigurationChanged(@Config int configChanges) { }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRecentAppsController.java
deleted file mode 100644
index acfbea3..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRecentAppsController.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.util.SparseArray;
-
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.quickstep.RecentsModel;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Provides recent apps functionality specifically in a desktop environment.
- */
-public class DesktopTaskbarRecentAppsController extends TaskbarRecentAppsController {
-
- private final TaskbarActivityContext mContext;
- private ArrayList<ItemInfo> mRunningApps = new ArrayList<>();
- private AppInfo[] mApps;
-
- public DesktopTaskbarRecentAppsController(TaskbarActivityContext context) {
- mContext = context;
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mApps = null;
- }
-
- @Override
- protected void setApps(AppInfo[] apps) {
- mApps = apps;
- }
-
- @Override
- protected boolean isEnabled() {
- return true;
- }
-
- /**
- * Set mRunningApps to hold currently running applications using the list of currently running
- * tasks. Filtering is also done to ignore applications that are already on the taskbar in the
- * original hotseat.
- */
- @Override
- protected void updateRunningApps(SparseArray<ItemInfo> hotseatItems) {
- ArrayList<AppInfo> runningApps = getRunningAppsFromTasks();
- ArrayList<ItemInfo> filteredRunningApps = new ArrayList<>();
- for (AppInfo runningApp : runningApps) {
- boolean shouldAddOnTaskbar = true;
- for (int i = 0; i < hotseatItems.size(); i++) {
- if (hotseatItems.keyAt(i) >= mControllers.taskbarActivityContext.getDeviceProfile()
- .numShownHotseatIcons) {
- break;
- }
- if (hotseatItems.valueAt(i).getTargetPackage()
- .equals(runningApp.getTargetPackage())) {
- shouldAddOnTaskbar = false;
- break;
- }
- }
- if (shouldAddOnTaskbar) {
- filteredRunningApps.add(new WorkspaceItemInfo(runningApp));
- }
- }
- mRunningApps = filteredRunningApps;
- mControllers.taskbarViewController.commitRunningAppsToUI();
- }
-
- /**
- * Returns a copy of hotseatItems with the addition of currently running applications.
- */
- @Override
- protected ItemInfo[] updateHotseatItemInfos(ItemInfo[] hotseatItemInfos) {
- // hotseatItemInfos.length would be 0 if deviceProfile.numShownHotseatIcons is 0, so we
- // don't want to show anything in the hotseat
- if (hotseatItemInfos.length == 0) return hotseatItemInfos;
-
- int runningAppsIndex = 0;
- ItemInfo[] newHotseatItemsInfo = Arrays.copyOf(
- hotseatItemInfos, hotseatItemInfos.length + mRunningApps.size());
- for (int i = hotseatItemInfos.length; i < newHotseatItemsInfo.length; i++) {
- newHotseatItemsInfo[i] = mRunningApps.get(runningAppsIndex);
- runningAppsIndex++;
- }
- return newHotseatItemsInfo;
- }
-
-
- /**
- * Returns a list of running applications from the list of currently running tasks.
- */
- private ArrayList<AppInfo> getRunningAppsFromTasks() {
- ArrayList<ActivityManager.RunningTaskInfo> tasks =
- RecentsModel.INSTANCE.get(mContext).getRunningTasks();
- ArrayList<AppInfo> runningApps = new ArrayList<>();
- // early return if apps is empty, since we would have no AppInfo to compare
- if (mApps == null) {
- return runningApps;
- }
-
- Set<String> seenPackages = new HashSet<>();
- for (ActivityManager.RunningTaskInfo taskInfo : tasks) {
- if (taskInfo.realActivity == null) continue;
-
- // If a different task for the same package has already been handled, skip this one
- String taskPackage = taskInfo.realActivity.getPackageName();
- if (seenPackages.contains(taskPackage)) continue;
-
- // Otherwise, get the corresponding AppInfo and add it to the list
- seenPackages.add(taskPackage);
- AppInfo app = getAppInfo(taskInfo.realActivity);
- if (app == null) continue;
- runningApps.add(app);
- }
- return runningApps;
- }
-
- /**
- * Retrieves the corresponding AppInfo for the activity.
- */
- private AppInfo getAppInfo(ComponentName activity) {
- String packageName = activity.getPackageName();
- for (AppInfo app : mApps) {
- if (!packageName.equals(app.getTargetPackage())) {
- continue;
- }
- return app;
- }
- return null;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
new file mode 100644
index 0000000..3649c4e
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
+import android.util.Log
+import android.util.SparseArray
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.valueIterator
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import kotlin.collections.filterNotNull
+
+/**
+ * Shows running apps when in Desktop Mode.
+ *
+ * Users can enter and exit Desktop Mode at run-time, meaning this class falls back to the default
+ * recent-apps behaviour when outside of Desktop Mode.
+ *
+ * This class should only be used if
+ * [com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps] is enabled.
+ */
+class DesktopTaskbarRunningAppsController(
+ private val recentsModel: RecentsModel,
+ // Pass a provider here instead of the actual DesktopVisibilityController instance since that
+ // instance might not be available when this constructor is called.
+ private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?,
+) : TaskbarRecentAppsController() {
+
+ private var apps: Array<AppInfo>? = null
+ private var allRunningDesktopAppInfos: List<AppInfo>? = null
+
+ private val desktopVisibilityController: DesktopVisibilityController?
+ get() = desktopVisibilityControllerProvider()
+
+ private val isInDesktopMode: Boolean
+ get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
+
+ override fun onDestroy() {
+ super.onDestroy()
+ apps = null
+ }
+
+ @VisibleForTesting
+ public override fun setApps(apps: Array<AppInfo>?) {
+ this.apps = apps
+ }
+
+ override fun isEnabled() = true
+
+ @VisibleForTesting
+ public override fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
+ if (!isInDesktopMode) {
+ Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode")
+ return hotseatItems
+ }
+ val newHotseatItemInfos =
+ hotseatItems
+ .filterNotNull()
+ // Ignore predicted apps - we show running apps instead
+ .filter { itemInfo -> !itemInfo.isPredictedItem }
+ .toMutableList()
+ val runningDesktopAppInfos =
+ allRunningDesktopAppInfos?.let {
+ getRunningDesktopAppInfosExceptHotseatApps(it, newHotseatItemInfos.toList())
+ }
+ if (runningDesktopAppInfos != null) {
+ newHotseatItemInfos.addAll(runningDesktopAppInfos)
+ }
+ return newHotseatItemInfos.toTypedArray()
+ }
+
+ override fun getRunningApps(): Set<String> {
+ if (!isInDesktopMode) {
+ return emptySet()
+ }
+ return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
+ }
+
+ @VisibleForTesting
+ public override fun updateRunningApps() {
+ if (!isInDesktopMode) {
+ Log.d(TAG, "updateRunningApps: not in Desktop Mode")
+ mControllers.taskbarViewController.commitRunningAppsToUI()
+ return
+ }
+ allRunningDesktopAppInfos = getRunningDesktopAppInfos()
+ mControllers.taskbarViewController.commitRunningAppsToUI()
+ }
+
+ private fun getRunningDesktopAppInfosExceptHotseatApps(
+ allRunningDesktopAppInfos: List<AppInfo>,
+ hotseatItems: List<ItemInfo>
+ ): List<ItemInfo> {
+ val hotseatPackages = hotseatItems.map { it.targetPackage }
+ return allRunningDesktopAppInfos
+ .filter { appInfo -> !hotseatPackages.contains(appInfo.targetPackage) }
+ .map { WorkspaceItemInfo(it) }
+ }
+
+ private fun getRunningDesktopAppInfos(): List<AppInfo> {
+ return getAppInfosFromRunningTasks(
+ recentsModel.runningTasks
+ .filter { taskInfo: RunningTaskInfo ->
+ taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
+ }
+ .toList()
+ )
+ }
+
+ // TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
+ private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
+ // Early return if apps is empty, since we then have no AppInfo to compare to
+ if (apps == null) {
+ return emptyList()
+ }
+ val packageNames = tasks.map { it.realActivity?.packageName }.distinct().filterNotNull()
+ return packageNames
+ .map { packageName -> apps?.find { app -> packageName == app.targetPackage } }
+ .filterNotNull()
+ }
+
+ private fun <E> SparseArray<E>.toList(): List<E> {
+ return valueIterator().asSequence().toList()
+ }
+
+ companion object {
+ private const val TAG = "TabletDesktopTaskbarRunningAppsController"
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
deleted file mode 100644
index 2dd610c4..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
+++ /dev/null
@@ -1,62 +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.taskbar;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.quickstep.util.TISBindHelper;
-
-/**
- * A data source which integrates with a Launcher instance, used specifically for a
- * desktop environment.
- */
-public class DesktopTaskbarUIController extends TaskbarUIController {
-
- private final QuickstepLauncher mLauncher;
-
- public DesktopTaskbarUIController(QuickstepLauncher launcher) {
- mLauncher = launcher;
- }
-
- @SuppressWarnings("MissingSuperCall") // TODO: Fix me
- @Override
- protected void init(TaskbarControllers taskbarControllers) {
- super.init(taskbarControllers);
- mLauncher.getHotseat().setIconsAlpha(0f);
- mControllers.taskbarViewController.updateRunningApps();
- }
-
- @SuppressWarnings("MissingSuperCall") // TODO: Fix me
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mLauncher.getHotseat().setIconsAlpha(1f);
- }
-
- /** Disable taskbar stashing in desktop environment. */
- @Override
- public boolean supportsVisualStashing() {
- return false;
- }
-
- @Nullable
- @Override
- protected TISBindHelper getTISBindHelper() {
- return mLauncher.getTISBindHelper();
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index c0ecc61..06d9ee6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -133,4 +133,9 @@
protected TISBindHelper getTISBindHelper() {
return mRecentsActivity.getTISBindHelper();
}
+
+ @Override
+ protected String getTaskbarUIControllerName() {
+ return "FallbackTaskbarUIController";
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 489102f..4f02122 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
-import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
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;
@@ -25,10 +24,6 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.TaskTransitionSpec;
-import android.view.WindowManagerGlobal;
import android.window.RemoteTransition;
import androidx.annotation.NonNull;
@@ -38,7 +33,6 @@
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.logging.InstanceId;
@@ -140,7 +134,6 @@
mLauncher.setTaskbarUIController(null);
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
mHomeState.removeListener(mVisibilityChangeListener);
- updateTaskTransitionSpec(true);
}
private void onInAppDisplayProgressChanged() {
@@ -279,26 +272,6 @@
private void onStashedInAppChanged(DeviceProfile deviceProfile) {
boolean taskbarStashedInApps = mControllers.taskbarStashController.isStashedInApp();
deviceProfile.isTaskbarPresentInApps = !taskbarStashedInApps;
- updateTaskTransitionSpec(taskbarStashedInApps);
- }
-
- private void updateTaskTransitionSpec(boolean taskbarIsHidden) {
- try {
- if (taskbarIsHidden) {
- // Clear custom task transition settings when the taskbar is stashed
- WindowManagerGlobal.getWindowManagerService().clearTaskTransitionSpec();
- } else {
- // Adjust task transition spec to account for taskbar being visible
- WindowManagerGlobal.getWindowManagerService().setTaskTransitionSpec(
- new TaskTransitionSpec(
- mLauncher.getColor(R.color.taskbar_background)));
- }
- } catch (RemoteException e) {
- // This shouldn't happen but if it does task animations won't look good until the
- // taskbar stashing state is changed.
- Log.e(TAG, "Failed to update task transition spec to account for new taskbar state",
- e);
- }
}
/**
@@ -306,8 +279,8 @@
*/
public void showEduOnAppLaunch() {
if (!shouldShowEduOnAppLaunch()) {
- // Called in case the edu finishes and circle to search edu is still pending
- mControllers.taskbarEduTooltipController.maybeShowCircleToSearchEdu();
+ // Called in case the edu finishes and search edu is still pending
+ mControllers.taskbarEduTooltipController.maybeShowSearchEdu();
return;
}
@@ -473,4 +446,9 @@
mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
}
+
+ @Override
+ protected String getTaskbarUIControllerName() {
+ return "LauncherTaskbarUIController";
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 2c5aeb3..abb763a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -317,38 +317,28 @@
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
-
- // Rotation button
- RotationButton rotationButton = new RotationButtonImpl(
- addButton(mEndContextualContainer, R.id.rotate_suggestion,
- R.layout.taskbar_contextual_button));
- rotationButton.hide();
- mControllers.rotationButtonController.setRotationButton(rotationButton, null);
- } else {
- mFloatingRotationButton = new FloatingRotationButton(
- ENABLE_TASKBAR_NAVBAR_UNIFICATION ? mNavigationBarPanelContext : mContext,
- R.string.accessibility_rotate_button,
- R.layout.rotate_suggestion,
- R.id.rotate_suggestion,
- R.dimen.floating_rotation_button_min_margin,
- R.dimen.rounded_corner_content_padding,
- R.dimen.floating_rotation_button_taskbar_left_margin,
- R.dimen.floating_rotation_button_taskbar_bottom_margin,
- R.dimen.floating_rotation_button_diameter,
- R.dimen.key_button_ripple_max_width,
- R.bool.floating_rotation_button_position_left);
- mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
- mRotationButtonListener);
-
- if (!mIsImeRenderingNavButtons) {
- View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
- mStartContextualContainer, mControllers.navButtonController, R.id.back);
- imeDownButton.setRotation(Utilities.isRtl(resources) ? 90 : -90);
- // Only show when IME is visible.
- mPropertyHolders.add(new StatePropertyHolder(imeDownButton,
- flags -> (flags & FLAG_IME_VISIBLE) != 0));
- }
+ } else if (!mIsImeRenderingNavButtons) {
+ View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
+ mStartContextualContainer, mControllers.navButtonController, R.id.back);
+ imeDownButton.setRotation(Utilities.isRtl(resources) ? 90 : -90);
+ // Only show when IME is visible.
+ mPropertyHolders.add(new StatePropertyHolder(imeDownButton,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0));
}
+ mFloatingRotationButton = new FloatingRotationButton(
+ ENABLE_TASKBAR_NAVBAR_UNIFICATION ? mNavigationBarPanelContext : mContext,
+ R.string.accessibility_rotate_button,
+ R.layout.rotate_suggestion,
+ R.id.rotate_suggestion,
+ R.dimen.floating_rotation_button_min_margin,
+ R.dimen.rounded_corner_content_padding,
+ R.dimen.floating_rotation_button_taskbar_left_margin,
+ R.dimen.floating_rotation_button_taskbar_bottom_margin,
+ R.dimen.floating_rotation_button_diameter,
+ R.dimen.key_button_ripple_max_width,
+ R.bool.floating_rotation_button_position_left);
+ mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
+ mRotationButtonListener);
applyState();
mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
@@ -386,8 +376,15 @@
(flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
(flags & FLAG_KEYGUARD_OCCLUDED) != 0;
return (flags & FLAG_DISABLE_BACK) == 0
+ && (!mContext.isGestureNav() || !mContext.isUserSetupComplete())
&& ((flags & FLAG_KEYGUARD_VISIBLE) == 0 || showingOnKeyguard);
}));
+ // Hide back button in SUW if keyboard is showing (IME draws its own back).
+ if (mIsImeRenderingNavButtons) {
+ mPropertyHolders.add(new StatePropertyHolder(
+ mBackButtonAlpha.get(ALPHA_INDEX_SUW),
+ flags -> (flags & FLAG_IME_VISIBLE) == 0));
+ }
mPropertyHolders.add(new StatePropertyHolder(mBackButton,
flags -> (flags & FLAG_IME_VISIBLE) != 0,
ROTATION_DRAWABLE_PERCENT, 1f, 0f));
@@ -410,8 +407,8 @@
mPropertyHolders.add(
new StatePropertyHolder(mHomeButtonAlpha.get(
ALPHA_INDEX_KEYGUARD_OR_DISABLE),
- flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
- (flags & FLAG_DISABLE_HOME) == 0));
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
+ && (flags & FLAG_DISABLE_HOME) == 0 && !mContext.isGestureNav()));
// Recents button
mRecentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
@@ -429,7 +426,7 @@
});
mPropertyHolders.add(new StatePropertyHolder(mRecentsButton,
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
- && !mContext.isNavBarKidsModeActive()));
+ && !mContext.isNavBarKidsModeActive() && !mContext.isGestureNav()));
// A11y button
mA11yButton = addButton(R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
@@ -791,7 +788,6 @@
NavButtonLayoutter navButtonLayoutter =
NavButtonLayoutFactory.Companion.getUiLayoutter(
dp, mNavButtonsView, mImeSwitcherButton,
- mControllers.rotationButtonController.getRotationButton(),
mA11yButton, mSpace, res, isInKidsMode, isInSetup, isThreeButtonNav,
mContext.isPhoneMode(), mWindowManagerProxy.getRotation(mContext));
navButtonLayoutter.layoutButtons(mContext, isA11yButtonPersistent());
@@ -802,13 +798,6 @@
if (isInSetup) {
handleSetupUi();
-
- // Hide back button in SUW if keyboard is showing (IME draws its own back).
- if (mIsImeRenderingNavButtons) {
- mPropertyHolders.add(new StatePropertyHolder(
- mBackButtonAlpha.get(ALPHA_INDEX_SUW),
- flags -> (flags & FLAG_IME_VISIBLE) == 0));
- }
} else if (isInKidsMode) {
int iconSize = res.getDimensionPixelSize(
R.dimen.taskbar_icon_size_kids);
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
index 83e4571..94e2244 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
@@ -15,9 +15,12 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
@@ -111,4 +114,17 @@
setBackgroundColor(newColor);
}
}
+
+ /**
+ * Updates the handle scale.
+ *
+ * @param scale target scale to animate towards (starting from current scale)
+ * @param durationMs milliseconds for the animation to take
+ */
+ public void animateScale(float scale, long durationMs) {
+ ObjectAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(SCALE_PROPERTY, scale));
+ scaleAnim.setDuration(durationMs).setAutoCancel(true);
+ scaleAnim.start();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index f258b47..36e054a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -57,6 +57,10 @@
public static final int ALPHA_INDEX_HIDDEN_WHILE_DREAMING = 3;
private static final int NUM_ALPHA_CHANNELS = 4;
+ // Values for long press animations, picked to most closely match navbar spec.
+ private static final float SCALE_TOUCH_ANIMATION_SHRINK = 0.85f;
+ private static final float SCALE_TOUCH_ANIMATION_EXPAND = 1.18f;
+
/**
* The SharedPreferences key for whether the stashed handle region is dark.
*/
@@ -324,7 +328,13 @@
@Override
public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {
- // TODO(b/308693847): Animate similarly to NavigationHandle.java (SysUI).
+ float targetScale;
+ if (isTouchDown) {
+ targetScale = shrink ? SCALE_TOUCH_ANIMATION_SHRINK : SCALE_TOUCH_ANIMATION_EXPAND;
+ } else {
+ targetScale = 1f;
+ }
+ mStashedHandleView.animateScale(targetScale, durationMs);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 49d4afe..af053e3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static android.content.pm.PackageManager.FEATURE_PC;
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -41,6 +40,8 @@
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -105,6 +106,7 @@
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
import com.android.launcher3.taskbar.bubbles.BubbleDragController;
+import com.android.launcher3.taskbar.bubbles.BubblePinController;
import com.android.launcher3.taskbar.bubbles.BubbleStashController;
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
@@ -127,7 +129,9 @@
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.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
@@ -244,8 +248,6 @@
mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
- final boolean isDesktopMode = getPackageManager().hasSystemFeature(FEATURE_PC);
-
// If Bubble bar is present, TaskbarControllers depends on it so build it first.
Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
BubbleBarController.onTaskbarRecreated();
@@ -258,7 +260,9 @@
new BubbleDragController(this),
new BubbleDismissController(this, mDragLayer),
new BubbleBarPinController(this, mDragLayer,
- () -> getDeviceProfile().getDisplayInfo().currentSize)
+ () -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
+ new BubblePinController(this, mDragLayer,
+ () -> DisplayController.INSTANCE.get(this).getInfo().currentSize)
));
}
@@ -271,16 +275,12 @@
R.drawable.ic_sysbar_rotate_button_cw_start_0,
R.drawable.ic_sysbar_rotate_button_cw_start_90,
() -> getDisplay().getRotation());
- rotationButtonController.setBgExecutor(Executors.THREAD_POOL_EXECUTOR);
+ rotationButtonController.setBgExecutor(Executors.UI_HELPER_EXECUTOR);
mControllers = new TaskbarControllers(this,
new TaskbarDragController(this),
buttonController,
- isDesktopMode
- ? new DesktopNavbarButtonsViewController(this, mNavigationBarPanelContext,
- navButtonsView)
- : new NavbarButtonsViewController(this, mNavigationBarPanelContext,
- navButtonsView),
+ new NavbarButtonsViewController(this, mNavigationBarPanelContext, navButtonsView),
rotationButtonController,
new TaskbarDragLayerController(this, mDragLayer),
new TaskbarViewController(this, taskbarView),
@@ -301,17 +301,26 @@
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
- isDesktopMode
- ? new DesktopTaskbarRecentAppsController(this)
- : TaskbarRecentAppsController.DEFAULT,
- new TaskbarEduTooltipController(this),
+ createTaskbarRecentAppsController(),
+ TaskbarEduTooltipController.newInstance(this),
new KeyboardQuickSwitchController(),
- new TaskbarPinningController(this),
+ new TaskbarPinningController(this, () ->
+ DisplayController.INSTANCE.get(this).getInfo().isInDesktopMode()),
bubbleControllersOptional);
mLauncherPrefs = LauncherPrefs.get(this);
}
+ private TaskbarRecentAppsController createTaskbarRecentAppsController() {
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ if (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()) {
+ return new DesktopTaskbarRunningAppsController(
+ RecentsModel.INSTANCE.get(this),
+ LauncherActivityInterface.INSTANCE::getDesktopVisibilityController);
+ }
+ return TaskbarRecentAppsController.DEFAULT;
+ }
+
/** Updates {@link DeviceProfile} instances for any Taskbar windows. */
public void updateDeviceProfile(DeviceProfile launcherDp) {
applyDeviceProfile(launcherDp);
@@ -956,7 +965,9 @@
mWindowLayoutParams.paramsForRotation[rot].height = size;
}
}
- mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
+ mControllers.runAfterInit(
+ mControllers.taskbarInsetsController
+ ::onTaskbarOrBubblebarWindowHeightOrInsetsChanged);
notifyUpdateLayoutParams();
}
@@ -1442,7 +1453,7 @@
});
}
- protected boolean isUserSetupComplete() {
+ public boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
@@ -1478,7 +1489,8 @@
((LauncherTaskbarUIController) uiController).addLauncherVisibilityChangedAnimation(
fullAnimation, duration);
}
- mControllers.taskbarStashController.addUnstashToHotseatAnimation(fullAnimation, duration);
+ mControllers.taskbarStashController.addUnstashToHotseatAnimationFromSuw(fullAnimation,
+ duration);
View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView();
if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 189b687..4f5922c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -74,12 +74,14 @@
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.LogUtils;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.systemui.shared.recents.model.Task;
@@ -163,11 +165,6 @@
return false;
}
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onTaskbarItemLongClick");
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.TWO_TASKBAR_LONG_CLICKS,
- "TaskbarDragController.startDragOnLongClick",
- new Throwable());
- }
BubbleTextView btv = (BubbleTextView) view;
mActivity.onDragStart();
btv.post(() -> {
@@ -340,8 +337,13 @@
@Override
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) {
+ if (mDisallowGlobalDrag || (desktopController != null
+ && desktopController.areDesktopTasksVisible())) {
AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS);
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index e53f627..d43055d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar
+import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@@ -42,8 +43,10 @@
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.launcher3.util.DisplayController
-import com.android.launcher3.util.OnboardingPrefs.TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN
import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN
+import com.android.launcher3.util.ResourceBasedOverride
+import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.BaseDragLayer
import com.android.quickstep.util.LottieAnimationColorUtils
import java.io.PrintWriter
@@ -72,9 +75,11 @@
annotation class TaskbarEduTooltipStep
/** Controls stepping through the Taskbar tooltip EDU. */
-class TaskbarEduTooltipController(val activityContext: TaskbarActivityContext) :
- LoggableTaskbarController {
+open class TaskbarEduTooltipController(context: Context) :
+ ResourceBasedOverride, LoggableTaskbarController {
+ protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+ open val shouldShowSearchEdu = false
private val isTooltipEnabled: Boolean
get() = !Utilities.isRunningInTestHarness() && !activityContext.isPhoneMode
private val isOpen: Boolean
@@ -83,13 +88,13 @@
get() = isTooltipEnabled && tooltipStep <= TOOLTIP_STEP_FEATURES
private lateinit var controllers: TaskbarControllers
- // Keep track of whether the user has seen the Circle to Search Edu
- private var userHasSeenCircleToSearchEdu: Boolean
+ // Keep track of whether the user has seen the Search Edu
+ private var userHasSeenSearchEdu: Boolean
get() {
- return TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN.get(activityContext)
+ return TASKBAR_SEARCH_EDU_SEEN.get(activityContext)
}
private set(seen) {
- LauncherPrefs.get(activityContext).put(TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN, seen)
+ LauncherPrefs.get(activityContext).put(TASKBAR_SEARCH_EDU_SEEN, seen)
}
@TaskbarEduTooltipStep
@@ -105,8 +110,8 @@
fun init(controllers: TaskbarControllers) {
this.controllers = controllers
- // We want to show the Circle To Search Edu right after pinning, so we post it here
- activityContext.dragLayer.post { maybeShowCircleToSearchEdu() }
+ // We want to show the Search Edu right after pinning the taskbar, so we post it here
+ activityContext.dragLayer.post { maybeShowSearchEdu() }
}
/** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
@@ -136,7 +141,7 @@
fun maybeShowFeaturesEdu() {
if (!isTooltipEnabled || tooltipStep > TOOLTIP_STEP_FEATURES) {
maybeShowPinningEdu()
- maybeShowCircleToSearchEdu()
+ maybeShowSearchEdu()
return
}
@@ -233,26 +238,26 @@
}
/**
- * Shows standalone Circle To Search EDU tooltip if this EDU has not been seen.
+ * Shows standalone Search EDU tooltip if this EDU has not been seen.
*
- * We show this standalone edu for users to learn to how to trigger Circle To Search from the
- * pinned taskbar
+ * We show this standalone edu for users to learn to how to trigger Search from the pinned
+ * taskbar
*/
- fun maybeShowCircleToSearchEdu() {
+ fun maybeShowSearchEdu() {
if (
!enableTaskbarPinning() ||
!DisplayController.isPinnedTaskbar(activityContext) ||
!isTooltipEnabled ||
- userHasSeenCircleToSearchEdu
+ !shouldShowSearchEdu ||
+ userHasSeenSearchEdu
) {
return
}
- userHasSeenCircleToSearchEdu = true
- inflateTooltip(R.layout.taskbar_edu_circle_to_search)
+ userHasSeenSearchEdu = true
+ inflateTooltip(R.layout.taskbar_edu_search)
tooltip?.run {
- requireViewById<LottieAnimationView>(R.id.circle_to_search_animation)
- .supportLightTheme()
- val eduSubtitle: TextView = requireViewById(R.id.circle_to_search_text)
+ requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
+ val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
showDisclosureText(eduSubtitle)
updateLayoutParams<BaseDragLayer.LayoutParams> {
if (DisplayController.isTransientTaskbar(activityContext)) {
@@ -285,7 +290,7 @@
*/
private fun TaskbarEduTooltip.showDisclosureText(
textView: TextView,
- stringId: Int = R.string.taskbar_edu_circle_to_search_disclosure,
+ stringId: Int = R.string.taskbar_edu_search_disclosure,
) {
val locale = resources.configuration.locales[0]
val text =
@@ -395,6 +400,17 @@
pw?.println("$prefix\tisOpen=$isOpen")
pw?.println("$prefix\ttooltipStep=$tooltipStep")
}
+
+ companion object {
+ @JvmStatic
+ fun newInstance(context: Context): TaskbarEduTooltipController {
+ return ResourceBasedOverride.Overrides.getObject(
+ TaskbarEduTooltipController::class.java,
+ context,
+ R.string.taskbar_edu_tooltip_controller_class
+ )
+ }
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 6163dad..4a8ed87 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -153,6 +153,19 @@
context.deviceProfile.widthPx,
windowLayoutParams.height
)
+
+ // if there's an animating bubble add it to the touch region so that it's clickable
+ val isAnimatingNewBubble =
+ controllers.bubbleControllers
+ .getOrNull()
+ ?.bubbleBarViewController
+ ?.isAnimatingNewBubble
+ ?: false
+ if (isAnimatingNewBubble) {
+ val iconBounds =
+ controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
+ defaultTouchableRegion.op(iconBounds, Region.Op.UNION)
+ }
}
// Pre-calculate insets for different providers across different rotations for this gravity
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index ee21eac..6ea52cb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -65,7 +65,7 @@
*/
public class TaskbarLauncherStateController {
- private static final String TAG = TaskbarLauncherStateController.class.getSimpleName();
+ private static final String TAG = "TaskbarLauncherStateController";
private static final boolean DEBUG = false;
/** Launcher activity is visible and focused. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index e47640b..42e6edb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar;
import static android.content.Context.RECEIVER_NOT_EXPORTED;
-import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
@@ -26,6 +25,7 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
@@ -62,6 +62,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
@@ -70,7 +71,6 @@
import com.android.quickstep.AllAppsActionManager;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.SystemUiProxy;
-import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.AssistUtils;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
@@ -143,7 +143,7 @@
private class RecreationListener implements DisplayController.DisplayInfoChangeListener {
@Override
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
- if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE
+ if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE
| CHANGE_TASKBAR_PINNING)) != 0) {
recreateTaskbar();
}
@@ -209,15 +209,18 @@
@SuppressLint("WrongConstant")
public TaskbarManager(
- TouchInteractionService service, AllAppsActionManager allAppsActionManager) {
+ Context context,
+ AllAppsActionManager allAppsActionManager,
+ TaskbarNavButtonCallbacks navCallbacks) {
+
Display display =
- service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
- mContext = service.createWindowContext(display,
+ context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
+ mContext = context.createWindowContext(display,
ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
null);
mAllAppsActionManager = allAppsActionManager;
mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
- ? service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
+ ? context.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
: null;
if (enableTaskbarNoRecreate()) {
mWindowManager = mContext.getSystemService(WindowManager.class);
@@ -234,8 +237,11 @@
}
};
}
- mNavButtonController = new TaskbarNavButtonController(service,
- SystemUiProxy.INSTANCE.get(mContext), new Handler(),
+ mNavButtonController = new TaskbarNavButtonController(
+ context,
+ navCallbacks,
+ SystemUiProxy.INSTANCE.get(mContext),
+ new Handler(),
AssistUtils.newInstance(mContext));
mComponentCallbacks = new ComponentCallbacks() {
private Configuration mOldConfig = mContext.getResources().getConfiguration();
@@ -420,9 +426,6 @@
*/
private TaskbarUIController createTaskbarUIControllerForActivity(StatefulActivity activity) {
if (activity instanceof QuickstepLauncher) {
- if (mTaskbarActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) {
- return new DesktopTaskbarUIController((QuickstepLauncher) activity);
- }
return new LauncherTaskbarUIController((QuickstepLauncher) activity);
}
if (activity instanceof RecentsActivity) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 14d46d1..9f24d38 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+
import android.util.SparseArray;
import android.view.View;
@@ -26,6 +29,7 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -33,6 +37,7 @@
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RecentsModel;
import java.io.PrintWriter;
@@ -42,6 +47,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.function.Predicate;
/**
@@ -62,6 +68,8 @@
// Used to defer any UI updates during the SUW unstash animation.
private boolean mDeferUpdatesForSUW;
private Runnable mDeferredUpdates;
+ private DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
+ visible -> updateRunningApps();
public TaskbarModelCallbacks(
TaskbarActivityContext context, TaskbarView container) {
@@ -73,6 +81,15 @@
mControllers = controllers;
if (mControllers.taskbarRecentAppsController.isEnabled()) {
RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
+
+ if (shouldShowRunningAppsInDesktopMode()) {
+ DesktopVisibilityController desktopVisibilityController =
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ if (desktopVisibilityController != null) {
+ desktopVisibilityController.registerDesktopVisibilityListener(
+ mDesktopVisibilityListener);
+ }
+ }
}
}
@@ -81,6 +98,20 @@
*/
public void unregisterListeners() {
RecentsModel.INSTANCE.get(mContext).unregisterRunningTasksListener();
+
+ if (shouldShowRunningAppsInDesktopMode()) {
+ DesktopVisibilityController desktopVisibilityController =
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ if (desktopVisibilityController != null) {
+ desktopVisibilityController.unregisterDesktopVisibilityListener(
+ mDesktopVisibilityListener);
+ }
+ }
+ }
+
+ private boolean shouldShowRunningAppsInDesktopMode() {
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
}
@Override
@@ -203,15 +234,23 @@
}
hotseatItemInfos = mControllers.taskbarRecentAppsController
.updateHotseatItemInfos(hotseatItemInfos);
+ Set<String> runningPackages = mControllers.taskbarRecentAppsController.getRunningApps();
if (mDeferUpdatesForSUW) {
ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
- mDeferredUpdates = () -> mContainer.updateHotseatItems(finalHotseatItemInfos);
+ mDeferredUpdates = () ->
+ commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages);
} else {
- mContainer.updateHotseatItems(hotseatItemInfos);
+ commitHotseatItemUpdates(hotseatItemInfos, runningPackages);
}
}
+ private void commitHotseatItemUpdates(
+ ItemInfo[] hotseatItemInfos, Set<String> runningPackages) {
+ mContainer.updateHotseatItems(hotseatItemInfos);
+ mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages);
+ }
+
/**
* This is used to defer UI updates after SUW builds the unstash animation.
* @param defer if true, defers updates to the UI
@@ -240,7 +279,7 @@
/** Call TaskbarRecentAppsController to update running apps with mHotseatItems. */
public void updateRunningApps() {
- mControllers.taskbarRecentAppsController.updateRunningApps(mHotseatItems);
+ mControllers.taskbarRecentAppsController.updateRunningApps();
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 03f55ca..13a68a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -31,6 +31,7 @@
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
@@ -47,10 +48,8 @@
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.quickstep.LauncherActivityInterface;
-import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
-import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.AssistUtils;
import java.io.PrintWriter;
@@ -67,7 +66,7 @@
/** Allow some time in between the long press for back and recents. */
static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200;
static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100;
- private static final String TAG = TaskbarNavButtonController.class.getSimpleName();
+ private static final String TAG = "TaskbarNavButtonController";
private long mLastScreenPinLongPress;
private boolean mScreenPinned;
@@ -106,7 +105,8 @@
private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS;
private int mLongPressedButtons = 0;
- private final TouchInteractionService mService;
+ private final Context mContext;
+ private final TaskbarNavButtonCallbacks mCallbacks;
private final SystemUiProxy mSystemUiProxy;
private final Handler mHandler;
private final AssistUtils mAssistUtils;
@@ -114,9 +114,14 @@
private final Runnable mResetLongPress = this::resetScreenUnpin;
- public TaskbarNavButtonController(TouchInteractionService service,
- SystemUiProxy systemUiProxy, Handler handler, AssistUtils assistUtils) {
- mService = service;
+ public TaskbarNavButtonController(
+ Context context,
+ TaskbarNavButtonCallbacks callbacks,
+ SystemUiProxy systemUiProxy,
+ Handler handler,
+ AssistUtils assistUtils) {
+ mContext = context;
+ mCallbacks = callbacks;
mSystemUiProxy = systemUiProxy;
mHandler = handler;
mAssistUtils = assistUtils;
@@ -286,7 +291,7 @@
desktopVisibilityController.onHomeActionTriggered();
}
- mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
+ mCallbacks.onNavigateHome();
}
private void navigateToOverview() {
@@ -295,7 +300,7 @@
}
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
- mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+ mCallbacks.onToggleOverview();
}
private void executeBack() {
@@ -310,7 +315,7 @@
if (longClick) {
mSystemUiProxy.notifyAccessibilityButtonLongClicked();
} else {
- mSystemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
+ mSystemUiProxy.notifyAccessibilityButtonClicked(mContext.getDisplayId());
}
}
@@ -333,4 +338,13 @@
private void showNotifications() {
mSystemUiProxy.toggleNotificationPanel();
}
+
+ /** Callbacks for navigation buttons on Taskbar. */
+ public interface TaskbarNavButtonCallbacks {
+ /** Callback invoked when the home button is pressed. */
+ default void onNavigateHome() {}
+
+ /** Callback invoked when the overview button is pressed. */
+ default void onToggleOverview() {}
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index 2f2d636..6c9cc64 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -23,6 +23,7 @@
import com.android.app.animation.Interpolators
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_PINNED
@@ -31,8 +32,10 @@
import java.io.PrintWriter
/** Controls taskbar pinning through a popup view. */
-class TaskbarPinningController(private val context: TaskbarActivityContext) :
- TaskbarControllers.LoggableTaskbarController {
+class TaskbarPinningController(
+ private val context: TaskbarActivityContext,
+ private val isInDesktopModeProvider: () -> Boolean,
+) : TaskbarControllers.LoggableTaskbarController {
private lateinit var controllers: TaskbarControllers
private lateinit var taskbarSharedState: TaskbarSharedState
@@ -54,14 +57,22 @@
if (!didPreferenceChange) {
return
}
+ val shouldPinTaskbar =
+ if (isInDesktopModeProvider()) {
+ !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
+ } else {
+ !launcherPrefs.get(TASKBAR_PINNING)
+ }
+
val animateToValue =
- if (!launcherPrefs.get(TASKBAR_PINNING)) {
+ if (shouldPinTaskbar) {
statsLogManager.logger().log(LAUNCHER_TASKBAR_PINNED)
PINNING_PERSISTENT
} else {
statsLogManager.logger().log(LAUNCHER_TASKBAR_UNPINNED)
PINNING_TRANSIENT
}
+
taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
animateTaskbarPinning(animateToValue)
}
@@ -123,13 +134,24 @@
@VisibleForTesting
fun recreateTaskbarAndUpdatePinningValue() {
updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
- launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
+ if (isInDesktopModeProvider()) {
+ launcherPrefs.put(
+ TASKBAR_PINNING_IN_DESKTOP_MODE,
+ !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
+ )
+ } else {
+ launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
+ }
}
override fun dumpLogs(prefix: String, pw: PrintWriter) {
pw.println(prefix + "TaskbarPinningController:")
pw.println("$prefix\tisAnimatingTaskbarPinning=$isAnimatingTaskbarPinning")
pw.println("$prefix\tTASKBAR_PINNING shared pref =" + launcherPrefs.get(TASKBAR_PINNING))
+ pw.println(
+ "$prefix\tTASKBAR_PINNING_IN_DESKTOP_MODE shared pref in desktop mode =" +
+ launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
+ )
}
companion object {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
index 8445cff..a29c74b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
@@ -15,13 +15,16 @@
*/
package com.android.launcher3.taskbar;
-import android.util.SparseArray;
+import static java.util.Collections.emptySet;
import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
+import java.util.Set;
+
/**
* Base class for providing recent apps functionality
*/
@@ -43,7 +46,8 @@
}
/** Stores the current {@link AppInfo} instances, no-op except in desktop environment. */
- protected void setApps(AppInfo[] apps) { }
+ protected void setApps(AppInfo[] apps) {
+ }
/**
* Indicates whether recent apps functionality is enabled, should return false except in
@@ -54,10 +58,15 @@
}
/** Called to update hotseatItems, no-op except in desktop environment. */
- protected ItemInfo[] updateHotseatItemInfos(ItemInfo[] hotseatItems) {
+ protected ItemInfo[] updateHotseatItemInfos(@NonNull ItemInfo[] hotseatItems) {
return hotseatItems;
}
/** Called to update the list of currently running apps, no-op except in desktop environment. */
- protected void updateRunningApps(SparseArray<ItemInfo> hotseatItems) { }
+ protected void updateRunningApps() {}
+
+ /** Returns the currently running apps, or an empty Set if outside of Desktop environment. */
+ public Set<String> getRunningApps() {
+ return emptySet();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 41c0586..f764a83 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -78,13 +78,13 @@
* create a cohesive animation between stashed/unstashed states.
*/
public class TaskbarStashController implements TaskbarControllers.LoggableTaskbarController {
- private static final String TAG = TaskbarStashController.class.getSimpleName();
+ private static final String TAG = "TaskbarStashController";
private static final boolean DEBUG = false;
public static final int FLAG_IN_APP = 1 << 0;
public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 1; // shade open, ...
public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 2; // setup wizard and AllSetActivity
- public static final int FLAG_STASHED_IN_APP_IME = 1 << 3; // IME is visible
+ public static final int FLAG_STASHED_IME = 1 << 3; // IME is visible
public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 4;
public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 5; // All apps is visible.
public static final int FLAG_IN_SETUP = 1 << 6; // In the Setup Wizard
@@ -99,21 +99,19 @@
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_SYSUI
- | FLAG_STASHED_IN_APP_SETUP | FLAG_STASHED_IN_APP_IME
- | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN
- | FLAG_STASHED_IN_APP_AUTO;
+ | FLAG_STASHED_IN_APP_SETUP | FLAG_STASHED_IN_TASKBAR_ALL_APPS
+ | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
// If any of these flags are enabled, inset apps by our stashed height instead of our unstashed
// height. This way the reported insets are consistent even during transitions out of the app.
// Currently any flag that causes us to stash in an app is included, except for IME or All Apps
// since those cover the underlying app anyway and thus the app shouldn't change insets.
private static final int FLAGS_REPORT_STASHED_INSETS_TO_APP = FLAGS_STASHED_IN_APP
- & ~FLAG_STASHED_IN_APP_IME & ~FLAG_STASHED_IN_TASKBAR_ALL_APPS
- & ~FLAG_STASHED_IN_APP_SYSUI;
+ & ~FLAG_STASHED_IME & ~FLAG_STASHED_IN_TASKBAR_ALL_APPS & ~FLAG_STASHED_IN_APP_SYSUI;
// If any of these flags are enabled, the taskbar must be stashed.
private static final int FLAGS_FORCE_STASHED = FLAG_STASHED_SYSUI | FLAG_STASHED_DEVICE_LOCKED
- | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN;
+ | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IME;
/**
* How long to stash/unstash when manually invoked via long press.
@@ -321,8 +319,7 @@
updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, isStashedInAppAuto);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
updateStateForFlag(FLAG_IN_SETUP, isInSetup);
- updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, mActivity.isPhoneMode()
- && !mActivity.isThreeButtonNav());
+ updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, mActivity.isPhoneGestureNavMode());
// For now, assume we're in an app, since LauncherTaskbarUIController won't be able to tell
// us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
updateStateForFlag(FLAG_IN_APP, true);
@@ -549,11 +546,12 @@
* sub-animations are properly coordinated. This duration should not
* actually be used since this animation tracks a swipe progress.
*/
- protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) {
+ protected void addUnstashToHotseatAnimationFromSuw(AnimatorSet animation,
+ int placeholderDuration) {
// Defer any UI updates now to avoid the UI becoming stale when the animation plays.
mControllers.taskbarViewController.setDeferUpdatesForSUW(true);
createAnimToIsStashed(
- /* isStashed= */ false,
+ /* isStashed= */ mActivity.isPhoneMode(),
placeholderDuration,
TRANSITION_UNSTASH_SUW_MANUAL,
/* jankTag= */ "SUW_MANUAL");
@@ -598,7 +596,7 @@
? stashTranslation : 0)
.setDuration(duration));
mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
- (hasAnyFlag(FLAG_STASHED_IN_APP_IME) && isStashed) ? 0 : 1).setDuration(
+ (hasAnyFlag(FLAG_STASHED_IME) && isStashed) ? 0 : 1).setDuration(
duration));
mAnimator.addListener(AnimatorListeners.forEndCallback(() -> {
mAnimator = null;
@@ -901,8 +899,8 @@
private void setStashedImeState() {
boolean shouldStashForIme = shouldStashForIme();
- if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != shouldStashForIme) {
- updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme);
+ if (hasAnyFlag(FLAG_STASHED_IME) != shouldStashForIme) {
+ updateStateForFlag(FLAG_STASHED_IME, shouldStashForIme);
applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
} else {
applyState(mControllers.taskbarOverlayController.getCloseDuration());
@@ -949,7 +947,7 @@
mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING);
- if (updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme())) {
+ if (updateStateForFlag(FLAG_STASHED_IME, shouldStashForIme())) {
animDuration = TASKBAR_STASH_DURATION_FOR_IME;
startDelay = getTaskbarStashStartDelayForIme();
}
@@ -1158,7 +1156,7 @@
appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_SYSUI, "FLAG_STASHED_IN_APP_SYSUI");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
- appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
+ appendFlag(sj, flags, FLAG_STASHED_IME, "FLAG_STASHED_IN_APP_IME");
appendFlag(sj, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE");
appendFlag(sj, flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS, "FLAG_STASHED_IN_TASKBAR_ALL_APPS");
appendFlag(sj, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP");
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 2e78489..6abd5a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -44,7 +44,7 @@
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import java.io.PrintWriter;
@@ -55,7 +55,6 @@
* Base class for providing different taskbar UI
*/
public class TaskbarUIController {
-
public static final TaskbarUIController DEFAULT = new TaskbarUIController();
// Initialized in init.
@@ -91,6 +90,10 @@
*/
protected void onIconLayoutBoundsChanged() { }
+ protected String getTaskbarUIControllerName() {
+ return "TaskbarUIController";
+ }
+
/** Called when an icon is launched. */
@CallSuper
public void onTaskbarIconLaunched(ItemInfo item) {
@@ -207,7 +210,7 @@
pw.println(String.format(
"%sTaskbarUIController: using an instance of %s",
prefix,
- getClass().getSimpleName()));
+ getTaskbarUIControllerName()));
}
/**
@@ -259,14 +262,14 @@
if (foundTaskView != null) {
// There is already a running app of this type, use that as second app.
// Get index of task (0 or 1), in case it's a GroupedTaskView
- TaskIdAttributeContainer taskAttributes =
- foundTaskView.getTaskAttributesById(foundTask.key.id);
+ TaskContainer taskContainer =
+ foundTaskView.getTaskContainerById(foundTask.key.id);
recents.confirmSplitSelect(
foundTaskView,
foundTask,
- taskAttributes.getIconView().getDrawable(),
- taskAttributes.getThumbnailView(),
- taskAttributes.getThumbnailView().getThumbnail(),
+ taskContainer.getIconView().getDrawable(),
+ taskContainer.getThumbnailView(),
+ taskContainer.getThumbnailView().getThumbnail(),
null /* intent */,
null /* user */,
info);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index effef3c..df7a7ba 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR;
@@ -72,7 +71,7 @@
*/
public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable,
DeviceProfile.OnDeviceProfileChangeListener {
- private static final String TAG = TaskbarView.class.getSimpleName();
+ private static final String TAG = "TaskbarView";
private static final Rect sTmpRect = new Rect();
@@ -157,23 +156,21 @@
// Needed to draw folder leave-behind when opening one.
setWillNotDraw(false);
- if (!mActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) {
- 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));
+ 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));
- if (enableTaskbarPinning()) {
- 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);
- }
+ if (enableTaskbarPinning()) {
+ 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);
}
// TODO: Disable touch events on QSB otherwise it can crash.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 5d0eac3..93814b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
@@ -71,6 +72,7 @@
import com.android.launcher3.views.IconButtonView;
import java.io.PrintWriter;
+import java.util.Set;
import java.util.function.Predicate;
/**
@@ -78,7 +80,7 @@
*/
public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController {
- private static final String TAG = TaskbarViewController.class.getSimpleName();
+ private static final String TAG = "TaskbarViewController";
private static final Runnable NO_OP = () -> { };
@@ -507,6 +509,15 @@
return mTaskbarView.getTaskbarDividerView();
}
+ /** Updates which icons are marked as running given the Set of currently running packages. */
+ public void updateIconViewsRunningStates(Set<String> runningPackages) {
+ for (View iconView : getIconViews()) {
+ if (iconView instanceof BubbleTextView btv) {
+ btv.updateRunningState(runningPackages.contains(btv.getTargetPackageName()));
+ }
+ }
+ }
+
/**
* Defers any updates to the UI for the setup wizard animation.
*/
@@ -679,6 +690,12 @@
&& mIsStashed) {
// Prevent All Apps icon from appearing when going from hotseat to nav handle.
setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0f, 0f));
+ } else if (enableScalingRevealHomeAnimation()) {
+ // Tighten clamp so that these icons do not linger as the spring settles.
+ setter.setViewAlpha(child, 0,
+ isToHome
+ ? Interpolators.clampToProgress(LINEAR, 0f, 0.07f)
+ : Interpolators.clampToProgress(LINEAR, 0.93f, 1f));
} else {
setter.setViewAlpha(child, 0,
isToHome
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 9799349..a59e81b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -22,13 +22,12 @@
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
-import android.graphics.drawable.ShapeDrawable
import com.android.app.animation.Interpolators
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
-import com.android.wm.shell.common.TriangleShape
+import com.android.launcher3.popup.RoundedArrowDrawable
/** Drawable for the background of the bubble bar. */
class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
@@ -37,7 +36,10 @@
private val LIGHT_THEME_SHADOW_ALPHA = 25f
private val paint: Paint = Paint()
- private val pointerSize: Float
+ private val pointerWidth: Float
+ private val pointerHeight: Float
+ private val pointerTipRadius: Float
+ private val pointerVisibleHeight: Float
private val shadowAlpha: Float
private var shadowBlur = 0f
@@ -47,7 +49,7 @@
private set
private var showingArrow: Boolean = false
- private var arrowDrawable: ShapeDrawable
+ private var arrowDrawable: RoundedArrowDrawable
var width: Float = 0f
@@ -75,7 +77,10 @@
val res = context.resources
shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
- pointerSize = res.getDimension(R.dimen.bubblebar_pointer_size)
+ pointerWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
+ pointerHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
+ pointerVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
+ pointerTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
shadowAlpha =
if (Utilities.isDarkTheme(context)) {
@@ -85,11 +90,14 @@
}
arrowDrawable =
- ShapeDrawable(TriangleShape.create(pointerSize, pointerSize, /* pointUp= */ true))
- arrowDrawable.setBounds(0, 0, pointerSize.toInt(), pointerSize.toInt())
- arrowDrawable.paint.flags = Paint.ANTI_ALIAS_FLAG
- arrowDrawable.paint.style = Paint.Style.FILL
- arrowDrawable.paint.color = context.getColor(R.color.taskbar_background)
+ RoundedArrowDrawable.createVerticalRoundedArrow(
+ pointerWidth,
+ pointerHeight,
+ pointerTipRadius,
+ /* isPointingUp= */ true,
+ context.getColor(R.color.taskbar_background)
+ )
+ arrowDrawable.setBounds(0, 0, pointerWidth.toInt(), pointerHeight.toInt())
}
fun showArrow(show: Boolean) {
@@ -114,7 +122,7 @@
keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
)
- arrowDrawable.paint.setShadowLayer(
+ arrowDrawable.setShadowLayer(
shadowBlur,
0f,
keyShadowDistance,
@@ -123,24 +131,16 @@
// Draw background.
val radius = backgroundHeight / 2f
- val left = if (anchorLeft) 0f else bounds.width().toFloat() - width
- val right = if (anchorLeft) width else bounds.width().toFloat()
- canvas.drawRoundRect(
- left,
- pointerSize,
- right,
- bounds.height().toFloat(),
- radius,
- radius,
- paint
- )
+ val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width)
+ val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat())
+ val top = bounds.top + pointerVisibleHeight
+ val bottom = bounds.top + bounds.height().toFloat()
+ canvas.drawRoundRect(left, top, right, bottom, radius, radius, paint)
if (showingArrow) {
// Draw arrow.
- val transX = arrowPositionX - pointerSize / 2f
- // Shift arrow down by 1 pixel. Rounded rect has a 1 pixel border which will show up
- // between background and arrow otherwise.
- canvas.translate(transX, 1f)
+ val transX = bounds.left + arrowPositionX - pointerWidth / 2f
+ canvas.translate(transX, 0f)
arrowDrawable.draw(canvas)
}
@@ -157,7 +157,8 @@
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
- arrowDrawable.paint.alpha = alpha
+ arrowDrawable.alpha = alpha
+ invalidateSelf()
}
override fun getAlpha(): Int {
@@ -169,7 +170,7 @@
}
fun setArrowAlpha(alpha: Int) {
- arrowDrawable.paint.alpha = alpha
+ arrowDrawable.alpha = alpha
}
fun setHeight(newHeight: Float) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 981c9f9..5789f0c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -94,7 +94,7 @@
*/
public class BubbleBarController extends IBubblesListener.Stub {
- private static final String TAG = BubbleBarController.class.getSimpleName();
+ private static final String TAG = "BubbleBarController";
private static final boolean DEBUG = false;
/**
@@ -150,6 +150,7 @@
private BubbleBarViewController mBubbleBarViewController;
private BubbleStashController mBubbleStashController;
private BubbleStashedHandleViewController mBubbleStashedHandleViewController;
+ private BubblePinController mBubblePinController;
// Keep track of bubble bar bounds sent to shell to avoid sending duplicate updates
private final Rect mLastSentBubbleBarBounds = new Rect();
@@ -169,6 +170,7 @@
BubbleBarLocation bubbleBarLocation;
List<RemovedBubble> removedBubbles;
List<String> bubbleKeysInOrder;
+ Point expandedViewDropTargetSize;
// These need to be loaded in the background
BubbleBarBubble addedBubble;
@@ -186,6 +188,7 @@
bubbleBarLocation = update.bubbleBarLocation;
removedBubbles = update.removedBubbles;
bubbleKeysInOrder = update.bubbleKeysInOrder;
+ expandedViewDropTargetSize = update.expandedViewDropTargetSize;
}
}
@@ -216,6 +219,7 @@
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleStashController = bubbleControllers.bubbleStashController;
mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
+ mBubblePinController = bubbleControllers.bubblePinController;
bubbleControllers.runAfterInit(() -> {
mBubbleBarViewController.setHiddenForBubbles(
@@ -403,9 +407,6 @@
}
if (bubbleToSelect != null) {
setSelectedBubbleInternal(bubbleToSelect);
- if (previouslySelectedBubble == null) {
- mBubbleStashController.animateToInitialState(update.expanded);
- }
}
if (update.shouldShowEducation) {
mBubbleBarViewController.prepareToShowEducation();
@@ -419,11 +420,12 @@
}
if (update.bubbleBarLocation != null) {
if (update.bubbleBarLocation != mBubbleBarViewController.getBubbleBarLocation()) {
- // Animate when receiving updates. Skip it if we received the initial state.
- boolean animate = !update.initialState;
- updateBubbleBarLocationInternal(update.bubbleBarLocation, animate);
+ updateBubbleBarLocationInternal(update.bubbleBarLocation);
}
}
+ if (update.expandedViewDropTargetSize != null) {
+ mBubblePinController.setDropTargetSize(update.expandedViewDropTargetSize);
+ }
}
/** Tells WMShell to show the currently selected bubble. */
@@ -483,15 +485,21 @@
* Updates the value locally in Launcher and in WMShell.
*/
public void updateBubbleBarLocation(BubbleBarLocation location) {
- updateBubbleBarLocationInternal(location, false /* animate */);
+ updateBubbleBarLocationInternal(location);
mSystemUiProxy.setBubbleBarLocation(location);
}
- private void updateBubbleBarLocationInternal(BubbleBarLocation location, boolean animate) {
- mBubbleBarViewController.setBubbleBarLocation(location, animate);
+ private void updateBubbleBarLocationInternal(BubbleBarLocation location) {
+ mBubbleBarViewController.setBubbleBarLocation(location);
mBubbleStashController.setBubbleBarLocation(location);
}
+ @Override
+ public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+ mMainExecutor.execute(
+ () -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation));
+ }
+
//
// Loading data for the bubbles
//
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index 8ed9949..9e5ffc9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -19,7 +19,6 @@
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Point
-import android.graphics.RectF
import android.view.Gravity.BOTTOM
import android.view.Gravity.LEFT
import android.view.Gravity.RIGHT
@@ -37,44 +36,29 @@
class BubbleBarPinController(
private val context: Context,
private val container: FrameLayout,
- private val screenSizeProvider: () -> Point
-) : BaseBubblePinController() {
+ screenSizeProvider: () -> Point
+) : BaseBubblePinController(screenSizeProvider) {
private lateinit var bubbleBarViewController: BubbleBarViewController
private lateinit var bubbleStashController: BubbleStashController
+ private var exclRectWidth: Float = 0f
+ private var exclRectHeight: Float = 0f
+
private var dropTargetView: View? = null
fun init(bubbleControllers: BubbleControllers) {
bubbleBarViewController = bubbleControllers.bubbleBarViewController
bubbleStashController = bubbleControllers.bubbleStashController
+ exclRectWidth = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width)
+ exclRectHeight = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
}
- override fun getScreenCenterX(): Int {
- return screenSizeProvider.invoke().x / 2
+ override fun getExclusionRectWidth(): Float {
+ return exclRectWidth
}
- override fun getExclusionRect(): RectF {
- val rect =
- RectF(
- 0f,
- 0f,
- context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width),
- context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
- )
- val screenSize = screenSizeProvider.invoke()
- val middleX = screenSize.x / 2
- // Center it around the bottom center of the screen
- rect.offsetTo(middleX - rect.width() / 2, screenSize.y - rect.height())
- return rect
- }
-
- override fun createDropTargetView(): View {
- return LayoutInflater.from(context)
- .inflate(R.layout.bubble_bar_drop_target, container, false)
- .also { view ->
- dropTargetView = view
- container.addView(view)
- }
+ override fun getExclusionRectHeight(): Float {
+ return exclRectHeight
}
override fun getDropTargetView(): View? {
@@ -86,6 +70,15 @@
dropTargetView = null
}
+ override fun createDropTargetView(): View {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.bubble_bar_drop_target, container, false)
+ .also { view ->
+ dropTargetView = view
+ container.addView(view)
+ }
+ }
+
@SuppressLint("RtlHardcoded")
override fun updateLocation(location: BubbleBarLocation) {
val onLeft = location.isOnLeft(container.isLayoutRtl)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 1003c3f..f3ac1e4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar.bubbles;
import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import android.animation.Animator;
@@ -29,6 +30,7 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.util.LayoutDirection;
import android.util.Log;
import android.view.Gravity;
@@ -74,11 +76,12 @@
*/
public class BubbleBarView extends FrameLayout {
- private static final String TAG = BubbleBarView.class.getSimpleName();
+ private static final String TAG = "BubbleBarView";
// TODO: (b/273594744) calculate the amount of space we have and base the max on that
// if it's smaller than 5.
private static final int MAX_BUBBLES = 5;
+ private static final int MAX_VISIBLE_BUBBLES_COLLAPSED = 2;
private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
private static final int WIDTH_ANIMATION_DURATION_MS = 200;
@@ -94,6 +97,23 @@
// During fade in animation we shift the bubble bar 1/60th of the screen width
private static final float FADE_IN_ANIM_POSITION_SHIFT = 1 / 60f;
+ /**
+ * Custom property to set alpha value for the bar view while a bubble is being dragged.
+ * Skips applying alpha to the dragged bubble.
+ */
+ private static final FloatProperty<BubbleBarView> BUBBLE_DRAG_ALPHA =
+ new FloatProperty<>("bubbleDragAlpha") {
+ @Override
+ public void setValue(BubbleBarView bubbleBarView, float alpha) {
+ bubbleBarView.setAlphaDuringBubbleDrag(alpha);
+ }
+
+ @Override
+ public Float get(BubbleBarView bubbleBarView) {
+ return bubbleBarView.mAlphaDuringDrag;
+ }
+ };
+
private final BubbleBarBackground mBubbleBarBackground;
private boolean mIsAnimatingNewBubble = false;
@@ -117,9 +137,12 @@
private final float mDragElevation;
private final int mPointerSize;
+ private final Rect mTempBackgroundBounds = new Rect();
+
// Whether the bar is expanded (i.e. the bubble activity is being displayed).
private boolean mIsBarExpanded = false;
// The currently selected bubble view.
+ @Nullable
private BubbleView mSelectedBubbleView;
private BubbleBarLocation mBubbleBarLocation = BubbleBarLocation.DEFAULT;
// The click listener when the bubble bar is collapsed.
@@ -149,11 +172,12 @@
@Nullable
private BubbleView mDraggedBubbleView;
+ private float mAlphaDuringDrag = 1f;
+
+ private Controller mController;
private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED;
- private boolean mLocationChangePending;
-
public BubbleBarView(Context context) {
this(context, null);
}
@@ -177,16 +201,17 @@
R.dimen.bubblebar_expanded_icon_spacing);
mBubbleElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_elevation);
mDragElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_drag_elevation);
- mPointerSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_pointer_size);
+ mPointerSize = getResources()
+ .getDimensionPixelSize(R.dimen.bubblebar_pointer_visible_size);
setClipToPadding(false);
- mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarHeight());
+ mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarExpandedHeight());
setBackgroundDrawable(mBubbleBarBackground);
mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
mWidthAnimator.addUpdateListener(animation -> {
- updateChildrenRenderNodeProperties();
+ updateChildrenRenderNodeProperties(mBubbleBarLocation);
invalidate();
});
mWidthAnimator.addListener(new Animator.AnimatorListener() {
@@ -204,6 +229,7 @@
// If the bar was just collapsed and the overflow was the last bubble that was
// selected, set the first bubble as selected.
if (!mIsBarExpanded && mUpdateSelectedBubbleAfterCollapse != null
+ && mSelectedBubbleView != null
&& mSelectedBubbleView.getBubble() instanceof BubbleBarOverflow) {
BubbleView firstBubble = (BubbleView) getChildAt(0);
mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
@@ -222,6 +248,17 @@
});
}
+ @Override
+ public void setTranslationX(float translationX) {
+ super.setTranslationX(translationX);
+ if (mDraggedBubbleView != null) {
+ // Apply reverse of the translation as an offset to the dragged view. This ensures
+ // that the dragged bubble stays at the current location on the screen and its
+ // position is not affected by the parent translation.
+ mDraggedBubbleView.setOffsetX(-translationX);
+ }
+ }
+
/**
* Sets new icon size and spacing between icons and bubble bar borders.
*
@@ -241,7 +278,7 @@
params.width = (int) mIconSize;
childView.setLayoutParams(params);
}
- mBubbleBarBackground.setHeight(getBubbleBarHeight());
+ mBubbleBarBackground.setHeight(getBubbleBarExpandedHeight());
updateLayoutParams();
}
@@ -258,8 +295,10 @@
setPivotX(mRelativePivotX * getWidth());
setPivotY(mRelativePivotY * getHeight());
- // Position the views
- updateChildrenRenderNodeProperties();
+ if (!mDragging) {
+ // Position the views when not dragging
+ updateChildrenRenderNodeProperties(mBubbleBarLocation);
+ }
}
@Override
@@ -275,15 +314,12 @@
@SuppressLint("RtlHardcoded")
private void onBubbleBarLocationChanged() {
- mLocationChangePending = false;
final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
mBubbleBarBackground.setAnchorLeft(onLeft);
mRelativePivotX = onLeft ? 0f : 1f;
- if (getLayoutParams() instanceof LayoutParams lp) {
- lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
- setLayoutParams(lp);
- }
- invalidate();
+ LayoutParams lp = (LayoutParams) getLayoutParams();
+ lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
+ setLayoutParams(lp); // triggers a relayout
}
/**
@@ -296,16 +332,16 @@
/**
* Update {@link BubbleBarLocation}
*/
- public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
- if (animate) {
- animateToBubbleBarLocation(bubbleBarLocation);
- } else {
- setBubbleBarLocationInternal(bubbleBarLocation);
+ public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+ resetDragAnimation();
+ if (bubbleBarLocation != mBubbleBarLocation) {
+ mBubbleBarLocation = bubbleBarLocation;
+ onBubbleBarLocationChanged();
}
}
/**
- * Set whether this view is being currently being dragged
+ * Set whether this view is currently being dragged
*/
public void setIsDragging(boolean dragging) {
if (mDragging == dragging) {
@@ -313,51 +349,66 @@
}
mDragging = dragging;
setElevation(dragging ? mDragElevation : mBubbleElevation);
- if (!dragging && mLocationChangePending) {
- // During drag finish animation we may update the translation x value to shift the
- // bubble to the new drop target. Clear the translation here.
- setTranslationX(0f);
- onBubbleBarLocationChanged();
+ if (!mDragging) {
+ // Relayout after dragging to ensure that the dragged bubble is positioned correctly
+ requestLayout();
}
}
/**
- * Adjust resting position for the bubble bar while it is being dragged.
- * <p>
- * Bubble bar is laid out on left or right side of the screen. When it is being dragged to
- * the opposite side, the resting position should be on that side. Calculate any additional
- * translation that may be required to move the bubble bar to the new side.
+ * Get translation for bubble bar when drag is released and it needs to animate back to the
+ * resting position.
+ * Resting position is based on the supplied location. If the supplied location is different
+ * from the internal location that was used during bubble bar layout, translation values are
+ * calculated to position the bar at the desired location.
*
- * @param restingPosition relative resting position of the bubble bar from the laid out position
+ * @param initialTranslation initial bubble bar translation at the start of drag
+ * @param location desired location of the bubble bar when drag is released
+ * @return point with x and y values representing translation on x and y-axis
*/
- @SuppressLint("RtlHardcoded")
- void adjustRelativeRestingPosition(PointF restingPosition) {
- final boolean locationOnLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
- // Bubble bar is placed left or right with gravity. Check where it is currently.
- final int absoluteGravity = Gravity.getAbsoluteGravity(
- ((LayoutParams) getLayoutParams()).gravity, getLayoutDirection());
- final boolean gravityOnLeft =
- (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT;
-
- // Bubble bar is pinned to the same side per gravity and the desired location.
- // Resting translation does not need to be adjusted.
- if (locationOnLeft == gravityOnLeft) {
- return;
+ public PointF getBubbleBarDragReleaseTranslation(PointF initialTranslation,
+ BubbleBarLocation location) {
+ float dragEndTranslationX = initialTranslation.x;
+ if (getBubbleBarLocation().isOnLeft(isLayoutRtl()) != location.isOnLeft(isLayoutRtl())) {
+ // Bubble bar is laid out on left or right side of the screen. And the desired new
+ // location is on the other side. Calculate x translation value required to shift
+ // bubble bar from one side to the other.
+ final float shift = getDistanceFromOtherSide();
+ if (location.isOnLeft(isLayoutRtl())) {
+ // New location is on the left, shift left
+ // before -> |......ooo.| after -> |.ooo......|
+ dragEndTranslationX = -shift;
+ } else {
+ // New location is on the right, shift right
+ // before -> |.ooo......| after -> |......ooo.|
+ dragEndTranslationX = shift;
+ }
}
+ return new PointF(dragEndTranslationX, mController.getBubbleBarTranslationY());
+ }
- // Bubble bar is laid out on left or right side of the screen. And the desired new
- // location is on the other side. Calculate x translation value required to shift the
- // bubble bar from one side to the other.
- float x = getDistanceFromOtherSide();
- if (locationOnLeft) {
- // New location is on the left, shift left
- // before -> |......ooo.| after -> |.ooo......|
- restingPosition.x = -x;
- } else {
- // New location is on the right, shift right
- // before -> |.ooo......| after -> |......ooo.|
- restingPosition.x = x;
- }
+ /**
+ * Get translation for a bubble when drag is released and it needs to animate back to the
+ * resting position.
+ * Resting position is based on the supplied location. If the supplied location is different
+ * from the internal location that was used during bubble bar layout, translation values are
+ * calculated to position the bar at the desired location.
+ *
+ * @param initialTranslation initial bubble bar translation at the start of drag
+ * @param location desired location of the bubble bar when drag is released
+ * @return point with x and y values representing translation on x and y-axis
+ */
+ public PointF getDraggedBubbleReleaseTranslation(PointF initialTranslation,
+ BubbleBarLocation location) {
+ // Start with bubble bar translation
+ final PointF dragEndTranslation = new PointF(
+ getBubbleBarDragReleaseTranslation(initialTranslation, location));
+ // Apply individual bubble translation, as the order may have changed
+ int viewIndex = indexOfChild(mDraggedBubbleView);
+ dragEndTranslation.x += getExpandedBubbleTranslationX(viewIndex,
+ getChildCount(),
+ location.isOnLeft(isLayoutRtl()));
+ return dragEndTranslation;
}
private float getDistanceFromOtherSide() {
@@ -371,55 +422,46 @@
return (float) (displayWidth - getWidth() - margin);
}
- private void setBubbleBarLocationInternal(BubbleBarLocation bubbleBarLocation) {
- if (bubbleBarLocation != mBubbleBarLocation) {
- mBubbleBarLocation = bubbleBarLocation;
- if (mDragging) {
- mLocationChangePending = true;
- } else {
- onBubbleBarLocationChanged();
- invalidate();
- }
- }
- }
-
- private void animateToBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
- if (bubbleBarLocation == mBubbleBarLocation) {
- // nothing to do, already at expected location
- return;
- }
+ /**
+ * Animate bubble bar to the given location transiently. Does not modify the layout or the value
+ * returned by {@link #getBubbleBarLocation()}.
+ */
+ public void animateToBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
if (mBubbleBarLocationAnimator != null && mBubbleBarLocationAnimator.isRunning()) {
+ mBubbleBarLocationAnimator.removeAllListeners();
mBubbleBarLocationAnimator.cancel();
}
// Location animation uses two separate animators.
// First animator hides the bar.
- // After it completes, location update is sent to layout the bar in the new location.
+ // After it completes, bubble positions in the bar and arrow position is updated.
// Second animator is started to show the bar.
- mBubbleBarLocationAnimator = getLocationUpdateFadeOutAnimator();
+ mBubbleBarLocationAnimator = getLocationUpdateFadeOutAnimator(bubbleBarLocation);
mBubbleBarLocationAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- // Bubble bar is not visible, update the location
- setBubbleBarLocationInternal(bubbleBarLocation);
+ updateChildrenRenderNodeProperties(bubbleBarLocation);
+ mBubbleBarBackground.setAnchorLeft(bubbleBarLocation.isOnLeft(isLayoutRtl()));
+
// Animate it in
- mBubbleBarLocationAnimator = getLocationUpdateFadeInAnimator();
+ mBubbleBarLocationAnimator = getLocationUpdateFadeInAnimator(bubbleBarLocation);
mBubbleBarLocationAnimator.start();
}
});
mBubbleBarLocationAnimator.start();
}
- private AnimatorSet getLocationUpdateFadeOutAnimator() {
+ private Animator getLocationUpdateFadeOutAnimator(BubbleBarLocation newLocation) {
final float shift =
getResources().getDisplayMetrics().widthPixels * FADE_OUT_ANIM_POSITION_SHIFT;
- final float tx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
+ final boolean onLeft = newLocation.isOnLeft(isLayoutRtl());
+ final float tx = getTranslationX() + (onLeft ? -shift : shift);
- ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, TRANSLATION_X, tx)
+ ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, VIEW_TRANSLATE_X, tx)
.setDuration(FADE_OUT_ANIM_POSITION_DURATION_MS);
positionAnim.setInterpolator(EMPHASIZED_ACCELERATE);
- ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 0f)
+ ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, getLocationAnimAlphaProperty(), 0f)
.setDuration(FADE_OUT_ANIM_ALPHA_DURATION_MS);
alphaAnim.setStartDelay(FADE_OUT_ANIM_ALPHA_DELAY_MS);
@@ -428,19 +470,36 @@
return animatorSet;
}
- private Animator getLocationUpdateFadeInAnimator() {
+ private Animator getLocationUpdateFadeInAnimator(BubbleBarLocation newLocation) {
final float shift =
getResources().getDisplayMetrics().widthPixels * FADE_IN_ANIM_POSITION_SHIFT;
- final float startTx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
+
+ final boolean onLeft = newLocation.isOnLeft(isLayoutRtl());
+ final float startTx;
+ final float finalTx;
+ if (newLocation == mBubbleBarLocation) {
+ // Animated location matches layout location.
+ finalTx = 0;
+ } else {
+ // We are animating in to a transient location, need to move the bar accordingly.
+ finalTx = getDistanceFromOtherSide() * (onLeft ? -1 : 1);
+ }
+ if (onLeft) {
+ // Bar will be shown on the left side. Start point is shifted right.
+ startTx = finalTx + shift;
+ } else {
+ // Bar will be shown on the right side. Start point is shifted left.
+ startTx = finalTx - shift;
+ }
ValueAnimator positionAnim = new SpringAnimationBuilder(getContext())
.setStartValue(startTx)
- .setEndValue(0)
+ .setEndValue(finalTx)
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
.setStiffness(FADE_IN_ANIM_POSITION_SPRING_STIFFNESS)
.build(this, VIEW_TRANSLATE_X);
- ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 1f)
+ ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, getLocationAnimAlphaProperty(), 1f)
.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS);
AnimatorSet animatorSet = new AnimatorSet();
@@ -449,6 +508,49 @@
}
/**
+ * Get property that can be used to animate the alpha value for the bar.
+ * When a bubble is being dragged, uses {@link #BUBBLE_DRAG_ALPHA}.
+ * Falls back to {@link com.android.launcher3.LauncherAnimUtils#VIEW_ALPHA} otherwise.
+ */
+ private FloatProperty<? super BubbleBarView> getLocationAnimAlphaProperty() {
+ return mDraggedBubbleView == null ? VIEW_ALPHA : BUBBLE_DRAG_ALPHA;
+ }
+
+ /**
+ * Set alpha value for the bar while a bubble is being dragged.
+ * We can not update the alpha on the bar directly because the dragged bubble would be affected
+ * as well. As it is a child view.
+ * Instead, while a bubble is being dragged, set alpha on each child view, that is not the
+ * dragged view. And set an alpha on the background.
+ * This allows for the dragged bubble to remain visible while the bar is hidden during
+ * animation.
+ */
+ private void setAlphaDuringBubbleDrag(float alpha) {
+ mAlphaDuringDrag = alpha;
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ if (view != mDraggedBubbleView) {
+ view.setAlpha(alpha);
+ }
+ }
+ if (mBubbleBarBackground != null) {
+ mBubbleBarBackground.setAlpha((int) (255 * alpha));
+ }
+ }
+
+ private void resetDragAnimation() {
+ if (mBubbleBarLocationAnimator != null) {
+ mBubbleBarLocationAnimator.removeAllListeners();
+ mBubbleBarLocationAnimator.cancel();
+ mBubbleBarLocationAnimator = null;
+ }
+ setAlphaDuringBubbleDrag(1f);
+ setTranslationX(0f);
+ setAlpha(1f);
+ }
+
+ /**
* Updates the bounds with translation that may have been applied and returns the result.
*/
public Rect getBubbleBarBounds() {
@@ -469,6 +571,11 @@
requestLayout();
}
+ /** Like {@link #setRelativePivot(float, float)} but only updates pivot y. */
+ public void setRelativePivotY(float y) {
+ setRelativePivot(mRelativePivotX, y);
+ }
+
/**
* Get current relative pivot for X axis
*/
@@ -483,38 +590,14 @@
return mRelativePivotY;
}
- /** Prepares for animating a bubble while being stashed. */
- public void prepareForAnimatingBubbleWhileStashed(String bubbleKey) {
+ /** Notifies the bubble bar that a new bubble animation is starting. */
+ public void onAnimatingBubbleStarted() {
mIsAnimatingNewBubble = true;
- // we're about to animate the new bubble in. the new bubble has already been added to this
- // view, but we're currently stashed, so before we can start the animation we need make
- // everything else in the bubble bar invisible, except for the bubble that's being animated.
- setBackground(null);
- for (int i = 0; i < getChildCount(); i++) {
- final BubbleView view = (BubbleView) getChildAt(i);
- final String key = view.getBubble().getKey();
- if (!bubbleKey.equals(key)) {
- view.setVisibility(INVISIBLE);
- }
- }
- setVisibility(VISIBLE);
- setAlpha(1);
- setTranslationY(0);
- setScaleX(1);
- setScaleY(1);
}
- /** Resets the state after the bubble animation completed. */
+ /** Notifies the bubble bar that a new bubble animation is complete. */
public void onAnimatingBubbleCompleted() {
mIsAnimatingNewBubble = false;
- // setting the background triggers relayout so no need to explicitly invalidate after the
- // animation
- setBackground(mBubbleBarBackground);
- for (int i = 0; i < getChildCount(); i++) {
- final BubbleView view = (BubbleView) getChildAt(i);
- view.setVisibility(VISIBLE);
- view.setAlpha(1f);
- }
}
// TODO: (b/280605790) animate it
@@ -533,6 +616,10 @@
@Override
public void removeView(View view) {
super.removeView(view);
+ if (view == mSelectedBubbleView) {
+ mSelectedBubbleView = null;
+ mBubbleBarBackground.showArrow(false);
+ }
updateWidth();
}
@@ -544,7 +631,7 @@
private void updateLayoutParams() {
LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- lp.height = getBubbleBarHeight();
+ lp.height = (int) getBubbleBarExpandedHeight();
lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
setLayoutParams(lp);
}
@@ -559,13 +646,7 @@
* Updates the z order, positions, and badge visibility of the bubble views in the bar based
* on the expanded state.
*/
- private void updateChildrenRenderNodeProperties() {
- if (mIsAnimatingNewBubble) {
- // don't update bubbles if a new bubble animation is playing.
- // the bubble bar will redraw itself via onLayout after the animation.
- return;
- }
-
+ private void updateChildrenRenderNodeProperties(BubbleBarLocation bubbleBarLocation) {
final float widthState = (float) mWidthAnimator.getAnimatedValue();
final float currentWidth = getWidth();
final float expandedWidth = expandedWidth();
@@ -573,25 +654,29 @@
int bubbleCount = getChildCount();
final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
final boolean animate = getVisibility() == VISIBLE;
- final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
+ final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl());
+ // elevation state is opposite to widthState - when expanded all icons are flat
+ float elevationState = (1 - widthState);
for (int i = 0; i < bubbleCount; i++) {
BubbleView bv = (BubbleView) getChildAt(i);
+ if (bv == mDraggedBubbleView) {
+ // Skip the dragged bubble. Its translation is managed by the drag controller.
+ continue;
+ }
+ // Clear out drag translation and offset
+ bv.setDragTranslationX(0f);
+ bv.setOffsetX(0f);
+
bv.setTranslationY(ty);
// the position of the bubble when the bar is fully expanded
- final float expandedX;
+ final float expandedX = getExpandedBubbleTranslationX(i, bubbleCount, onLeft);
// the position of the bubble when the bar is fully collapsed
- final float collapsedX;
- if (onLeft) {
- // If bar is on the left, bubbles are ordered right to left
- expandedX = (bubbleCount - i - 1) * (mIconSize + mExpandedBarIconsSpacing);
- // Shift the first bubble only if there are more bubbles in addition to overflow
- collapsedX = i == 0 && bubbleCount > 2 ? mIconOverlapAmount : 0;
- } else {
- // Bubbles ordered left to right, don't move the first bubble
- expandedX = i * (mIconSize + mExpandedBarIconsSpacing);
- collapsedX = i == 0 ? 0 : mIconOverlapAmount;
- }
+ final float collapsedX = getCollapsedBubbleTranslationX(i, bubbleCount, onLeft);
+
+ // slowly animate elevation while keeping correct Z ordering
+ float fullElevationForChild = (MAX_BUBBLES * mBubbleElevation) - i;
+ bv.setZ(fullElevationForChild * elevationState);
if (mIsBarExpanded) {
// If bar is on the right, account for bubble bar expanding and shifting left
@@ -599,10 +684,6 @@
// where the bubble will end up when the animation ends
final float targetX = expandedX + expandedBarShift;
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
- // if we're fully expanded, set the z level to 0 or to bubble elevation if dragged
- if (widthState == 1f) {
- bv.setZ(bv == mDraggedBubbleView ? mBubbleElevation : 0);
- }
// When we're expanded, we're not stacked so we're not behind the stack
bv.setBehindStack(false, animate);
bv.setAlpha(1);
@@ -611,15 +692,15 @@
final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
final float targetX = collapsedX + collapsedBarShift;
bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
- bv.setZ((MAX_BUBBLES * mBubbleElevation) - i);
// If we're not the first bubble we're behind the stack
bv.setBehindStack(i > 0, animate);
// If we're fully collapsed, hide all bubbles except for the first 2. If there are
// only 2 bubbles, hide the second bubble as well because it's the overflow.
if (widthState == 0) {
- if (i > 1) {
+ if (i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
bv.setAlpha(0);
- } else if (i == 1 && bubbleCount == 2) {
+ } else if (i == MAX_VISIBLE_BUBBLES_COLLAPSED - 1
+ && bubbleCount == MAX_VISIBLE_BUBBLES_COLLAPSED) {
bv.setAlpha(0);
}
}
@@ -627,8 +708,9 @@
}
// update the arrow position
- final float collapsedArrowPosition = arrowPositionForSelectedWhenCollapsed();
- final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded();
+ final float collapsedArrowPosition = arrowPositionForSelectedWhenCollapsed(
+ bubbleBarLocation);
+ final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded(bubbleBarLocation);
final float interpolatedWidth =
widthState * (expandedWidth - collapsedWidth) + collapsedWidth;
final float arrowPosition;
@@ -651,6 +733,34 @@
mBubbleBarBackground.setWidth(interpolatedWidth);
}
+ private float getExpandedBubbleTranslationX(int bubbleIndex, int bubbleCount,
+ boolean onLeft) {
+ if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
+ return 0;
+ }
+ if (onLeft) {
+ // If bar is on the left, bubbles are ordered right to left
+ return (bubbleCount - bubbleIndex - 1) * (mIconSize + mExpandedBarIconsSpacing);
+ } else {
+ // Bubbles ordered left to right, don't move the first bubble
+ return bubbleIndex * (mIconSize + mExpandedBarIconsSpacing);
+ }
+ }
+
+ private float getCollapsedBubbleTranslationX(int bubbleIndex, int bubbleCount,
+ boolean onLeft) {
+ if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
+ return 0;
+ }
+ if (onLeft) {
+ // Shift the first bubble only if there are more bubbles in addition to overflow
+ return bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
+ ? mIconOverlapAmount : 0;
+ } else {
+ return bubbleIndex == 0 ? 0 : mIconOverlapAmount;
+ }
+ }
+
/**
* Reorders the views to match the provided list.
*/
@@ -675,7 +785,7 @@
addViewInLayout(child, i, child.getLayoutParams());
}
}
- updateChildrenRenderNodeProperties();
+ updateChildrenRenderNodeProperties(mBubbleBarLocation);
}
}
@@ -684,20 +794,34 @@
mUpdateSelectedBubbleAfterCollapse = updateSelectedBubbleAfterCollapse;
}
+ void setController(Controller controller) {
+ mController = controller;
+ }
+
/**
* Sets which bubble view should be shown as selected.
*/
public void setSelectedBubble(BubbleView view) {
+ BubbleView previouslySelectedBubble = mSelectedBubbleView;
mSelectedBubbleView = view;
- updateArrowForSelected(/* shouldAnimate= */ true);
+ mBubbleBarBackground.showArrow(view != null);
+ // TODO: (b/283309949) remove animation should be implemented first, so than arrow
+ // animation is adjusted, skip animation for now
+ updateArrowForSelected(previouslySelectedBubble != null);
}
/**
* Sets the dragged bubble view to correctly apply Z order. Dragged view should appear on top
*/
public void setDraggedBubble(@Nullable BubbleView view) {
+ if (mDraggedBubbleView != null) {
+ mDraggedBubbleView.setZ(0);
+ }
mDraggedBubbleView = view;
- requestLayout();
+ if (view != null) {
+ view.setZ(mDragElevation);
+ }
+ setIsDragging(view != null);
}
/**
@@ -712,8 +836,12 @@
return;
}
// Find the center of the bubble when it's expanded, set the arrow position to it.
- final float tx = arrowPositionForSelectedWhenExpanded();
+ final float tx = arrowPositionForSelectedWhenExpanded(mBubbleBarLocation);
final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX();
+ if (tx == currentArrowPosition) {
+ // arrow position remains unchanged
+ return;
+ }
if (shouldAnimate && currentArrowPosition > expandedWidth()) {
Log.d(TAG, "arrow out of bounds of expanded view, skip animation");
shouldAnimate = false;
@@ -733,10 +861,10 @@
}
}
- private float arrowPositionForSelectedWhenExpanded() {
+ private float arrowPositionForSelectedWhenExpanded(BubbleBarLocation bubbleBarLocation) {
final int index = indexOfChild(mSelectedBubbleView);
final int bubblePosition;
- if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+ if (bubbleBarLocation.isOnLeft(isLayoutRtl())) {
// Bubble positions are reversed. First bubble is on the right.
bubblePosition = getChildCount() - index - 1;
} else {
@@ -746,13 +874,13 @@
+ mIconSize / 2f;
}
- private float arrowPositionForSelectedWhenCollapsed() {
+ private float arrowPositionForSelectedWhenCollapsed(BubbleBarLocation bubbleBarLocation) {
final int index = indexOfChild(mSelectedBubbleView);
final int bubblePosition;
- if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+ if (bubbleBarLocation.isOnLeft(isLayoutRtl())) {
// Bubble positions are reversed. First bubble may be shifted, if there are more
// bubbles than the current bubble and overflow.
- bubblePosition = index == 0 && getChildCount() > 2 ? 1 : 0;
+ bubblePosition = index == 0 && getChildCount() > MAX_VISIBLE_BUBBLES_COLLAPSED ? 1 : 0;
} else {
bubblePosition = index;
}
@@ -814,13 +942,18 @@
final int horizontalPadding = getPaddingStart() + getPaddingEnd();
// If there are more than 2 bubbles, the first 2 should be visible when collapsed.
// Otherwise just the first bubble should be visible because we don't show the overflow.
- return childCount > 2
+ return childCount > MAX_VISIBLE_BUBBLES_COLLAPSED
? mIconSize + mIconOverlapAmount + horizontalPadding
: mIconSize + horizontalPadding;
}
- private int getBubbleBarHeight() {
- return (int) (mIconSize + mBubbleBarPadding * 2 + mPointerSize);
+ private float getBubbleBarExpandedHeight() {
+ return getBubbleBarCollapsedHeight() + mPointerSize;
+ }
+
+ float getBubbleBarCollapsedHeight() {
+ // the pointer is invisible when collapsed
+ return mIconSize + mBubbleBarPadding * 2;
}
/**
@@ -837,10 +970,28 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mIsAnimatingNewBubble) {
+ mController.onBubbleBarTouchedWhileAnimating();
+ }
if (!mIsBarExpanded) {
// When the bar is collapsed, all taps on it should expand it.
return true;
}
return super.onInterceptTouchEvent(ev);
}
+
+ /** Whether a new bubble is currently animating. */
+ public boolean isAnimatingNewBubble() {
+ return mIsAnimatingNewBubble;
+ }
+
+ /** Interface for BubbleBarView to communicate with its controller. */
+ interface Controller {
+
+ /** 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();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index a1a2898..fbdb2ed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -20,6 +20,7 @@
import android.content.res.Resources;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -54,7 +55,7 @@
*/
public class BubbleBarViewController {
- private static final String TAG = BubbleBarViewController.class.getSimpleName();
+ private static final String TAG = "BubbleBarViewController";
private static final float APP_ICON_SMALL_DP = 44f;
private static final float APP_ICON_MEDIUM_DP = 48f;
private static final float APP_ICON_LARGE_DP = 52f;
@@ -131,6 +132,17 @@
});
mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
+ mBarView.setController(new BubbleBarView.Controller() {
+ @Override
+ public float getBubbleBarTranslationY() {
+ return mBubbleStashController.getBubbleBarTranslationY();
+ }
+
+ @Override
+ public void onBubbleBarTouchedWhileAnimating() {
+ BubbleBarViewController.this.onBubbleBarTouchedWhileAnimating();
+ }
+ });
}
private void onBubbleClicked(View v) {
@@ -138,6 +150,7 @@
if (bubble == null) {
Log.e(TAG, "bubble click listener, bubble was null");
}
+
final String currentlySelected = mBubbleBarController.getSelectedBubbleKey();
if (mBarView.isExpanded() && Objects.equals(bubble.getKey(), currentlySelected)) {
// Tapping the currently selected bubble while expanded collapses the view.
@@ -148,6 +161,11 @@
}
}
+ private void onBubbleBarTouchedWhileAnimating() {
+ mBubbleBarViewAnimator.onBubbleBarTouchedWhileAnimating();
+ mBubbleStashController.onNewBubbleAnimationInterrupted(false, mBarView.getTranslationY());
+ }
+
private void onBubbleBarClicked() {
if (mShouldShowEducation) {
mShouldShowEducation = false;
@@ -159,10 +177,21 @@
// Show user education relative to the reference point
mSystemUiProxy.showUserEducation(position);
} else {
+ // ensure that the bubble bar has the correct translation. we may have just interrupted
+ // the animation by touching the bubble bar.
+ mBubbleBarTranslationY.animateToValue(mBubbleStashController.getBubbleBarTranslationY())
+ .start();
setExpanded(true);
}
}
+ /** Notifies that the stash state is changing. */
+ public void onStashStateChanging() {
+ if (isAnimatingNewBubble()) {
+ mBubbleBarViewAnimator.onStashStateChangingWhileAnimating();
+ }
+ }
+
//
// The below animators are exposed to BubbleStashController so it can manage the stashing
// animation.
@@ -180,6 +209,10 @@
return mBubbleBarTranslationY;
}
+ float getBubbleBarCollapsedHeight() {
+ return mBarView.getBubbleBarCollapsedHeight();
+ }
+
/**
* Whether the bubble bar is visible or not.
*/
@@ -202,8 +235,17 @@
/**
* Update bar {@link BubbleBarLocation}
*/
- public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
- mBarView.setBubbleBarLocation(bubbleBarLocation, animate);
+ public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+ mBarView.setBubbleBarLocation(bubbleBarLocation);
+ }
+
+ /**
+ * Animate bubble bar to the given location. The location change is transient. It does not
+ * update the state of the bubble bar.
+ * To update bubble bar pinned location, use {@link #setBubbleBarLocation(BubbleBarLocation)}.
+ */
+ public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+ mBarView.animateToBubbleBarLocation(bubbleBarLocation);
}
/**
@@ -213,6 +255,11 @@
return mBarView.getBubbleBarBounds();
}
+ /** Whether a new bubble is animating. */
+ public boolean isAnimatingNewBubble() {
+ return mBarView.isAnimatingNewBubble();
+ }
+
/** The horizontal margin of the bubble bar from the edge of the screen. */
public int getHorizontalMargin() {
return mBarView.getHorizontalMargin();
@@ -371,11 +418,21 @@
return;
}
- boolean isStashedOrGone =
- mBubbleStashController.isStashed() || mBarView.getVisibility() != VISIBLE;
- // don't animate the new bubble if we're auto expanding from stashed
- if (b instanceof BubbleBarBubble && isStashedOrGone && !isExpanding) {
- mBubbleBarViewAnimator.animateBubbleInForStashed((BubbleBarBubble) b);
+ if (!(b instanceof BubbleBarBubble bubble)) {
+ return;
+ }
+
+ 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) {
+ mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
+ return;
+ }
+
+ // only animate the new bubble if we're in an app and not auto expanding
+ if (isInApp && !isExpanding && !isExpanded()) {
+ mBubbleBarViewAnimator.animateBubbleInForStashed(bubble);
}
} else {
Log.w(TAG, "addBubble, bubble was null!");
@@ -442,7 +499,8 @@
*/
public void onDragStart(@NonNull BubbleView bubbleView) {
if (bubbleView.getBubble() == null) return;
- mSystemUiProxy.onBubbleDrag(bubbleView.getBubble().getKey(), /* isBeingDragged = */ true);
+
+ mSystemUiProxy.startBubbleDrag(bubbleView.getBubble().getKey());
mBarView.setDraggedBubble(bubbleView);
}
@@ -450,18 +508,49 @@
* Notifies SystemUI to expand the selected bubble when the bubble is released.
* @param bubbleView dragged bubble view
*/
- public void onDragRelease(@NonNull BubbleView bubbleView) {
+ public void onDragRelease(@NonNull BubbleView bubbleView, BubbleBarLocation location) {
if (bubbleView.getBubble() == null) return;
- mSystemUiProxy.onBubbleDrag(bubbleView.getBubble().getKey(), /* isBeingDragged = */ false);
+ // TODO(b/330585402): send new bubble bar bounds to shell for the animation
+ mSystemUiProxy.stopBubbleDrag(bubbleView.getBubble().getKey(), location);
}
/**
- * Removes the dragged bubble view in the bubble bar view
+ * Notifies {@link BubbleBarView} that drag and all animations are finished.
*/
- public void onDragEnd() {
+ public void onDragBubbleEnded() {
mBarView.setDraggedBubble(null);
}
+ /** Notifies that dragging the bubble bar ended. */
+ public void onDragBubbleBarEnded() {
+ // we may have changed the bubble bar translation Y value from the value it had at the
+ // beginning of the drag, so update the translation Y animator state
+ mBubbleBarTranslationY.updateValue(mBarView.getTranslationY());
+ }
+
+ /**
+ * Get translation for bubble bar when drag is released.
+ *
+ * @see BubbleBarView#getBubbleBarDragReleaseTranslation(PointF, BubbleBarLocation)
+ */
+ public PointF getBubbleBarDragReleaseTranslation(PointF initialTranslation,
+ BubbleBarLocation location) {
+ return mBarView.getBubbleBarDragReleaseTranslation(initialTranslation, location);
+ }
+
+ /**
+ * Get translation for bubble view when drag is released.
+ *
+ * @see BubbleBarView#getDraggedBubbleReleaseTranslation(PointF, BubbleBarLocation)
+ */
+ public PointF getDraggedBubbleReleaseTranslation(PointF initialTranslation,
+ BubbleBarLocation location) {
+ if (location == mBarView.getBubbleBarLocation()) {
+ return initialTranslation;
+ }
+ return mBarView.getDraggedBubbleReleaseTranslation(initialTranslation, location);
+ }
+
/**
* Called when bubble was dragged into the dismiss target. Notifies System
* @param bubble dismissed bubble item
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index 90f1be3..295477c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -30,6 +30,7 @@
public final BubbleDragController bubbleDragController;
public final BubbleDismissController bubbleDismissController;
public final BubbleBarPinController bubbleBarPinController;
+ public final BubblePinController bubblePinController;
private final RunnableList mPostInitRunnables = new RunnableList();
@@ -45,7 +46,8 @@
BubbleStashedHandleViewController bubbleStashedHandleViewController,
BubbleDragController bubbleDragController,
BubbleDismissController bubbleDismissController,
- BubbleBarPinController bubbleBarPinController) {
+ BubbleBarPinController bubbleBarPinController,
+ BubblePinController bubblePinController) {
this.bubbleBarController = bubbleBarController;
this.bubbleBarViewController = bubbleBarViewController;
this.bubbleStashController = bubbleStashController;
@@ -53,6 +55,7 @@
this.bubbleDragController = bubbleDragController;
this.bubbleDismissController = bubbleDismissController;
this.bubbleBarPinController = bubbleBarPinController;
+ this.bubblePinController = bubblePinController;
}
/**
@@ -68,6 +71,7 @@
bubbleDragController.init(/* bubbleControllers = */ this);
bubbleDismissController.init(/* bubbleControllers = */ this);
bubbleBarPinController.init(this);
+ bubblePinController.init(this);
mPostInitRunnables.executeAllAndDestroy();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index a40f33c..0e6fa3c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -40,7 +40,7 @@
* @see BubbleDragController
*/
public class BubbleDismissController {
- private static final String TAG = BubbleDismissController.class.getSimpleName();
+ private static final String TAG = "BubbleDismissController";
private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f;
private final TaskbarActivityContext mActivity;
private final TaskbarDragLayer mDragLayer;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 8b811d9..287e906 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -60,6 +60,7 @@
private final float mBubbleFocusedScale;
private final float mBubbleCapturedScale;
private final float mDismissCapturedScale;
+ private final FloatPropertyCompat<View> mTranslationXProperty;
/**
* Should be initialised for each dragged view
@@ -81,9 +82,28 @@
if (view instanceof BubbleBarView) {
mBubbleFocusedScale = SCALE_BUBBLE_BAR_FOCUSED;
mBubbleCapturedScale = mDismissCapturedScale;
+ mTranslationXProperty = DynamicAnimation.TRANSLATION_X;
} else {
mBubbleFocusedScale = SCALE_BUBBLE_FOCUSED;
mBubbleCapturedScale = SCALE_BUBBLE_CAPTURED;
+ // Wrap BubbleView.DRAG_TRANSLATION_X as it can't be cast to FloatPropertyCompat<View>
+ mTranslationXProperty = new FloatPropertyCompat<>(
+ BubbleView.DRAG_TRANSLATION_X.getName()) {
+ @Override
+ public float getValue(View object) {
+ if (object instanceof BubbleView bubbleView) {
+ return BubbleView.DRAG_TRANSLATION_X.get(bubbleView);
+ }
+ return 0;
+ }
+
+ @Override
+ public void setValue(View object, float value) {
+ if (object instanceof BubbleView bubbleView) {
+ BubbleView.DRAG_TRANSLATION_X.setValue(bubbleView, value);
+ }
+ }
+ };
}
}
@@ -110,25 +130,25 @@
/**
* Animates the dragged bubble movement back to the initial position.
*
- * @param initialPosition the position to animate to
+ * @param restingPosition the position to animate to
* @param velocity the initial velocity to use for the spring animation
* @param endActions gets called when the animation completes or gets cancelled
*/
- public void animateToInitialState(@NonNull PointF initialPosition, @NonNull PointF velocity,
+ public void animateToRestingState(@NonNull PointF restingPosition, @NonNull PointF velocity,
@Nullable Runnable endActions) {
mBubbleAnimator.cancel();
mBubbleAnimator
.spring(DynamicAnimation.SCALE_X, 1f)
.spring(DynamicAnimation.SCALE_Y, 1f)
- .spring(DynamicAnimation.TRANSLATION_X, initialPosition.x, velocity.x,
+ .spring(mTranslationXProperty, restingPosition.x, velocity.x,
mTranslationConfig)
- .spring(DynamicAnimation.TRANSLATION_Y, initialPosition.y, velocity.y,
+ .spring(DynamicAnimation.TRANSLATION_Y, restingPosition.y, velocity.y,
mTranslationConfig)
.addEndListener((View target, @NonNull FloatPropertyCompat<? super View> property,
boolean wasFling, boolean canceled, float finalValue, float finalVelocity,
boolean allRelevantPropertyAnimationsEnded) -> {
if (canceled || allRelevantPropertyAnimationsEnded) {
- resetAnimatedViews(initialPosition);
+ resetAnimatedViews(restingPosition);
if (endActions != null) {
endActions.run();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 5ffc6d8..f4b393a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -26,6 +26,8 @@
import androidx.annotation.Nullable;
import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.wm.shell.common.bubbles.BaseBubblePinController.LocationChangeListener;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
/**
* Controls bubble bar drag interactions.
@@ -37,9 +39,11 @@
*/
public class BubbleDragController {
private final TaskbarActivityContext mActivity;
+ private BubbleBarController mBubbleBarController;
private BubbleBarViewController mBubbleBarViewController;
private BubbleDismissController mBubbleDismissController;
private BubbleBarPinController mBubbleBarPinController;
+ private BubblePinController mBubblePinController;
public BubbleDragController(TaskbarActivityContext activity) {
mActivity = activity;
@@ -51,13 +55,16 @@
* controllers may still be waiting for init().
*/
public void init(@NonNull BubbleControllers bubbleControllers) {
+ mBubbleBarController = bubbleControllers.bubbleBarController;
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleDismissController = bubbleControllers.bubbleDismissController;
mBubbleBarPinController = bubbleControllers.bubbleBarPinController;
- mBubbleBarPinController.setListener(
- bubbleControllers.bubbleBarController::updateBubbleBarLocation);
+ mBubblePinController = bubbleControllers.bubblePinController;
mBubbleDismissController.setListener(
- stuck -> mBubbleBarPinController.setDropTargetHidden(stuck));
+ stuck -> {
+ mBubbleBarPinController.setDropTargetHidden(stuck);
+ mBubblePinController.setDropTargetHidden(stuck);
+ });
}
/**
@@ -71,19 +78,60 @@
}
bubbleView.setOnTouchListener(new BubbleTouchListener() {
+
+ private BubbleBarLocation mReleasedLocation = BubbleBarLocation.DEFAULT;
+
+ private final LocationChangeListener mLocationChangeListener =
+ new LocationChangeListener() {
+ @Override
+ public void onChange(@NonNull BubbleBarLocation location) {
+ mBubbleBarController.animateBubbleBarLocation(location);
+ }
+
+ @Override
+ public void onRelease(@NonNull BubbleBarLocation location) {
+ mReleasedLocation = location;
+ }
+ };
+
@Override
void onDragStart() {
+ mBubblePinController.setListener(mLocationChangeListener);
mBubbleBarViewController.onDragStart(bubbleView);
+ mBubblePinController.onDragStart(
+ mBubbleBarViewController.getBubbleBarLocation().isOnLeft(
+ bubbleView.isLayoutRtl()));
}
@Override
- void onDragEnd() {
- mBubbleBarViewController.onDragEnd();
+ protected void onDragUpdate(float x, float y, float newTx, float newTy) {
+ bubbleView.setDragTranslationX(newTx);
+ bubbleView.setTranslationY(newTy);
+ mBubblePinController.onDragUpdate(x, y);
}
@Override
protected void onDragRelease() {
- mBubbleBarViewController.onDragRelease(bubbleView);
+ mBubblePinController.onDragEnd();
+ mBubbleBarViewController.onDragRelease(bubbleView, mReleasedLocation);
+ }
+
+ @Override
+ protected void onDragDismiss() {
+ mBubblePinController.onDragEnd();
+ }
+
+ @Override
+ void onDragEnd() {
+ mBubbleBarController.updateBubbleBarLocation(mReleasedLocation);
+ mBubbleBarViewController.onDragBubbleEnded();
+ mBubblePinController.setListener(null);
+ }
+
+ @Override
+ protected PointF getRestingPosition() {
+ return mBubbleBarViewController.getDraggedBubbleReleaseTranslation(
+ getInitialPosition(), mReleasedLocation);
}
});
}
@@ -96,6 +144,11 @@
PointF initialRelativePivot = new PointF();
bubbleBarView.setOnTouchListener(new BubbleTouchListener() {
+ private BubbleBarLocation mReleasedLocation = BubbleBarLocation.DEFAULT;
+
+ private final LocationChangeListener mLocationChangeListener =
+ location -> mReleasedLocation = location;
+
@Override
protected boolean onTouchDown(@NonNull View view, @NonNull MotionEvent event) {
if (bubbleBarView.isExpanded()) return false;
@@ -104,6 +157,7 @@
@Override
void onDragStart() {
+ mBubbleBarPinController.setListener(mLocationChangeListener);
initialRelativePivot.set(bubbleBarView.getRelativePivotX(),
bubbleBarView.getRelativePivotY());
// By default the bubble bar view pivot is in bottom right corner, while dragging
@@ -115,7 +169,9 @@
}
@Override
- protected void onDragUpdate(float x, float y) {
+ protected void onDragUpdate(float x, float y, float newTx, float newTy) {
+ bubbleBarView.setTranslationX(newTx);
+ bubbleBarView.setTranslationY(newTy);
mBubbleBarPinController.onDragUpdate(x, y);
}
@@ -131,16 +187,19 @@
@Override
void onDragEnd() {
+ // Make sure to update location as the first thing. Pivot update causes a relayout
+ mBubbleBarController.updateBubbleBarLocation(mReleasedLocation);
+ bubbleBarView.setIsDragging(false);
// Restoring the initial pivot for the bubble bar view
bubbleBarView.setRelativePivot(initialRelativePivot.x, initialRelativePivot.y);
- bubbleBarView.setIsDragging(false);
+ mBubbleBarViewController.onDragBubbleBarEnded();
+ mBubbleBarPinController.setListener(null);
}
@Override
protected PointF getRestingPosition() {
- PointF restingPosition = super.getRestingPosition();
- bubbleBarView.adjustRelativeRestingPosition(restingPosition);
- return restingPosition;
+ return mBubbleBarViewController.getBubbleBarDragReleaseTranslation(
+ getInitialPosition(), mReleasedLocation);
}
});
}
@@ -206,8 +265,7 @@
* Called when bubble is dragged to new coordinates.
* Not called while bubble is stuck to the dismiss target.
*/
- protected void onDragUpdate(float x, float y) {
- }
+ protected abstract void onDragUpdate(float x, float y, float newTx, float newTy);
/**
* Called when the dragging interaction has ended and all the animations have completed
@@ -229,6 +287,13 @@
}
/**
+ * Get the initial position of the view when drag started
+ */
+ protected PointF getInitialPosition() {
+ return mViewInitialPosition;
+ }
+
+ /**
* Get the resting position of the view when drag is released
*/
protected PointF getRestingPosition() {
@@ -345,9 +410,9 @@
private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy,
float x, float y) {
if (mBubbleDismissController.handleTouchEvent(event)) return;
- view.setTranslationX(mViewInitialPosition.x + dx);
- view.setTranslationY(mViewInitialPosition.y + dy);
- onDragUpdate(x, y);
+ final float newTx = mViewInitialPosition.x + dx;
+ final float newTy = mViewInitialPosition.y + dy;
+ onDragUpdate(x, y, newTx, newTy);
}
private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {
@@ -362,7 +427,7 @@
mAnimator.animateDismiss(mViewInitialPosition, onComplete);
} else {
onDragRelease();
- mAnimator.animateToInitialState(getRestingPosition(), getCurrentVelocity(),
+ mAnimator.animateToRestingState(getRestingPosition(), getCurrentVelocity(),
onComplete);
}
mBubbleDismissController.hideDismissView();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
new file mode 100644
index 0000000..a77e685
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Point
+import android.view.Gravity.BOTTOM
+import android.view.Gravity.LEFT
+import android.view.Gravity.RIGHT
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.view.updateLayoutParams
+import com.android.launcher3.R
+import com.android.wm.shell.common.bubbles.BaseBubblePinController
+import com.android.wm.shell.common.bubbles.BubbleBarLocation
+
+/** Controller to manage pinning bubble bar to left or right when dragging starts from a bubble */
+class BubblePinController(
+ private val context: Context,
+ private val container: FrameLayout,
+ screenSizeProvider: () -> Point
+) : BaseBubblePinController(screenSizeProvider) {
+
+ var dropTargetSize: Point? = null
+
+ private lateinit var bubbleBarViewController: BubbleBarViewController
+ private lateinit var bubbleStashController: BubbleStashController
+ private var exclRectWidth: Float = 0f
+ private var exclRectHeight: Float = 0f
+
+ private var dropTargetView: View? = null
+ // Fallback width and height in case shell has not sent the size over
+ private var dropTargetDefaultWidth: Int = 0
+ private var dropTargetDefaultHeight: Int = 0
+ private var dropTargetMargin: Int = 0
+
+ fun init(bubbleControllers: BubbleControllers) {
+ bubbleBarViewController = bubbleControllers.bubbleBarViewController
+ bubbleStashController = bubbleControllers.bubbleStashController
+ exclRectWidth = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width)
+ exclRectHeight = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
+ dropTargetDefaultWidth =
+ context.resources.getDimensionPixelSize(
+ R.dimen.bubble_expanded_view_drop_target_default_width
+ )
+ dropTargetDefaultHeight =
+ context.resources.getDimensionPixelSize(
+ R.dimen.bubble_expanded_view_drop_target_default_height
+ )
+ dropTargetMargin =
+ context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_drop_target_margin)
+ }
+
+ override fun getExclusionRectWidth(): Float {
+ return exclRectWidth
+ }
+
+ override fun getExclusionRectHeight(): Float {
+ return exclRectHeight
+ }
+
+ override fun getDropTargetView(): View? {
+ return dropTargetView
+ }
+
+ override fun removeDropTargetView(view: View) {
+ container.removeView(view)
+ dropTargetView = null
+ }
+
+ override fun createDropTargetView(): View {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.bubble_expanded_view_drop_target, container, false)
+ .also { view ->
+ dropTargetView = view
+ container.addView(view)
+ }
+ }
+
+ @SuppressLint("RtlHardcoded")
+ override fun updateLocation(location: BubbleBarLocation) {
+ val onLeft = location.isOnLeft(container.isLayoutRtl)
+
+ val bubbleBarBounds = bubbleBarViewController.bubbleBarBounds
+ dropTargetView?.updateLayoutParams<FrameLayout.LayoutParams> {
+ gravity = BOTTOM or (if (onLeft) LEFT else RIGHT)
+ width = dropTargetSize?.x ?: dropTargetDefaultWidth
+ height = dropTargetSize?.y ?: dropTargetDefaultHeight
+ bottomMargin =
+ -bubbleStashController.bubbleBarTranslationY.toInt() +
+ bubbleBarBounds.height() +
+ dropTargetMargin
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 76d86de..5d01b9b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -25,6 +25,7 @@
import android.view.MotionEvent;
import android.view.View;
+import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.StashedHandleViewController;
import com.android.launcher3.taskbar.TaskbarActivityContext;
@@ -41,7 +42,7 @@
*/
public class BubbleStashController {
- private static final String TAG = BubbleStashController.class.getSimpleName();
+ private static final String TAG = "BubbleStashController";
/**
* How long to stash/unstash.
@@ -77,11 +78,16 @@
private boolean mBubblesShowingOnOverview;
private boolean mIsSysuiLocked;
+ private final float mHandleCenterFromScreenBottom;
+
@Nullable
private AnimatorSet mAnimator;
public BubbleStashController(TaskbarActivityContext activity) {
mActivity = activity;
+ // the handle is centered within the stashed taskbar area
+ mHandleCenterFromScreenBottom =
+ mActivity.getResources().getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f;
}
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -117,21 +123,17 @@
}
/**
- * Animates the bubble bar and handle to their initial state, transitioning from the state where
- * both views are invisible. Called when the first bubble is added or when the device is
+ * Animates the handle (or bubble bar depending on state) to be visible after the device is
* unlocked.
*
* <p>Normally either the bubble bar or the handle is visible,
* and {@link #showBubbleBar(boolean)} and {@link #stashBubbleBar()} are used to transition
* between these two states. But the transition from the state where both the bar and handle
* are invisible is slightly different.
- *
- * <p>The initial state will depend on the current state of the device, i.e. overview, home etc
- * and whether bubbles are requested to be expanded.
*/
- public void animateToInitialState(boolean expanding) {
+ private void animateAfterUnlock() {
AnimatorSet animatorSet = new AnimatorSet();
- if (expanding || mBubblesShowingOnHome || mBubblesShowingOnOverview) {
+ if (mBubblesShowingOnHome || mBubblesShowingOnOverview) {
mIsStashed = false;
animatorSet.playTogether(mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(getBubbleBarTranslationY()),
@@ -211,7 +213,7 @@
if (isSysuiLocked != mIsSysuiLocked) {
mIsSysuiLocked = isSysuiLocked;
if (!mIsSysuiLocked && mBarViewController.hasBubbles()) {
- animateToInitialState(false /* expanding */);
+ animateAfterUnlock();
}
}
}
@@ -244,6 +246,11 @@
&& !mBubblesShowingOnHome
&& !mBubblesShowingOnOverview;
if (mIsStashed != isStashed) {
+ // notify the view controller that the stash state is about to change so that it can
+ // cancel an ongoing animation if there is one.
+ // note that this has to be called before updating mIsStashed with the new value,
+ // otherwise interrupting an ongoing animation may update it again with the wrong state
+ mBarViewController.onStashStateChanging();
mIsStashed = isStashed;
if (mAnimator != null) {
mAnimator.cancel();
@@ -266,7 +273,6 @@
*/
private AnimatorSet createStashAnimator(boolean isStashed, long duration) {
AnimatorSet animatorSet = new AnimatorSet();
- final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f;
AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
// Not exactly half and may overlap. See [first|second]HalfDurationScale below.
@@ -280,7 +286,8 @@
firstHalfDurationScale = 0.75f;
secondHalfDurationScale = 0.5f;
- fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation));
+ fullLengthAnimatorSet.play(
+ mIconTranslationYForStash.animateToValue(getStashTranslation()));
firstHalfAnimatorSet.playTogether(
mIconAlphaForStash.animateToValue(0),
@@ -329,6 +336,10 @@
return animatorSet;
}
+ private float getStashTranslation() {
+ return (mUnstashedHeight - mStashedHeight) / 2f;
+ }
+
private void onIsStashedChanged() {
mControllers.runAfterInit(() -> {
mHandleViewController.onIsStashedChanged();
@@ -336,7 +347,7 @@
});
}
- private float getBubbleBarTranslationYForTaskbar() {
+ public float getBubbleBarTranslationYForTaskbar() {
return -mActivity.getDeviceProfile().taskbarBottomMargin;
}
@@ -347,7 +358,7 @@
hotseatCellHeight - mUnstashedHeight) / 2;
}
- float getBubbleBarTranslationY() {
+ public float getBubbleBarTranslationY() {
// If we're on home, adjust the translation so the bubble bar aligns with hotseat.
// Otherwise we're either showing in an app or in overview. In either case adjust it so
// the bubble bar aligns with the taskbar.
@@ -355,6 +366,25 @@
: getBubbleBarTranslationYForTaskbar();
}
+ /**
+ * The difference on the Y axis between the center of the handle and the center of the bubble
+ * bar.
+ */
+ public float getDiffBetweenHandleAndBarCenters() {
+ // the difference between the centers of the handle and the bubble bar is the difference
+ // between their distance from the bottom of the screen.
+
+ float barCenter = mBarViewController.getBubbleBarCollapsedHeight() / 2f;
+ return mHandleCenterFromScreenBottom - barCenter;
+ }
+
+ /** The distance the handle moves as part of the new bubble animation. */
+ public float getStashedHandleTranslationForNewBubbleAnimation() {
+ // the should move up to the top of the stashed taskbar area. it is centered within it so
+ // it should move the same distance as it is away from the bottom.
+ return -mHandleCenterFromScreenBottom;
+ }
+
/** Checks whether the motion event is over the stash handle. */
public boolean isEventOverStashHandle(MotionEvent ev) {
return mHandleViewController.isEventOverHandle(ev);
@@ -365,13 +395,63 @@
mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
}
- /** Returns the x position of the center of the stashed handle. */
- public float getStashedHandleCenterX() {
- return mHandleViewController.getStashedHandleCenterX();
- }
-
/** Returns the [PhysicsAnimator] for the stashed handle view. */
public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
return mHandleViewController.getPhysicsAnimator();
}
+
+ /** Notifies taskbar that it should update its touchable region. */
+ public void updateTaskbarTouchRegion() {
+ mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
+ }
+
+ /** Shows the bubble bar immediately without animation. */
+ public void showBubbleBarImmediate() {
+ mHandleViewController.setTranslationYForSwipe(0);
+ mIconTranslationYForStash.updateValue(getBubbleBarTranslationY());
+ mIconAlphaForStash.setValue(1);
+ mIconScaleForStash.updateValue(1);
+ mIsStashed = false;
+ onIsStashedChanged();
+ }
+
+ /** Stashes the bubble bar immediately without animation. */
+ public void stashBubbleBarImmediate() {
+ mHandleViewController.setTranslationYForSwipe(0);
+ mIconAlphaForStash.setValue(0);
+ mIconTranslationYForStash.updateValue(getStashTranslation());
+ mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
+ mIsStashed = true;
+ onIsStashedChanged();
+ }
+
+ /**
+ * Updates the values of the internal animators after the new bubble animation was interrupted
+ *
+ * @param isStashed whether the current state should be stashed
+ * @param bubbleBarTranslationY the current bubble bar translation. this is only used if the
+ * bubble bar is showing to ensure that the stash animator runs
+ * smoothly.
+ */
+ public void onNewBubbleAnimationInterrupted(boolean isStashed, float bubbleBarTranslationY) {
+ if (isStashed) {
+ mBubbleStashedHandleAlpha.setValue(1);
+ mIconAlphaForStash.setValue(0);
+ mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
+ mIconTranslationYForStash.updateValue(getStashTranslation());
+ } else {
+ mBubbleStashedHandleAlpha.setValue(0);
+ mHandleViewController.setTranslationYForSwipe(0);
+ mIconAlphaForStash.setValue(1);
+ mIconScaleForStash.updateValue(1);
+ mIconTranslationYForStash.updateValue(bubbleBarTranslationY);
+ }
+ mIsStashed = isStashed;
+ onIsStashedChanged();
+ }
+
+ /** Set the translation Y for the stashed handle. */
+ public void setHandleTranslationY(float ty) {
+ mHandleViewController.setTranslationYForSwipe(ty);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 6f1a093..91103d7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -251,11 +251,6 @@
return mStashedHandleAlpha;
}
- /** Returns the x position of the center of the stashed handle. */
- public float getStashedHandleCenterX() {
- return mStashedHandleBounds.exactCenterX();
- }
-
/**
* Creates and returns an Animator that updates the stashed handle shape and size.
* When stashed, the shape is a thin rounded pill. When unstashed, the shape morphs into
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index bcdc718..61a6bce 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -22,11 +22,13 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
@@ -47,6 +49,25 @@
public static final int DEFAULT_PATH_SIZE = 100;
/**
+ * Property to update drag translation value.
+ *
+ * @see BubbleView#getDragTranslationX()
+ * @see BubbleView#setDragTranslationX(float)
+ */
+ public static final FloatProperty<BubbleView> DRAG_TRANSLATION_X = new FloatProperty<>(
+ "dragTranslationX") {
+ @Override
+ public void setValue(@NonNull BubbleView bubbleView, float value) {
+ bubbleView.setDragTranslationX(value);
+ }
+
+ @Override
+ public Float get(BubbleView bubbleView) {
+ return bubbleView.getDragTranslationX();
+ }
+ };
+
+ /**
* Flags that suppress the visibility of the 'new' dot or the app badge, for one reason or
* another. If any of these flags are set, the dot will not be shown.
* If {@link SuppressionFlag#BEHIND_STACK} then the app badge will not be shown.
@@ -66,6 +87,9 @@
private final ImageView mAppIcon;
private final int mBubbleSize;
+ private float mDragTranslationX;
+ private float mOffsetX;
+
private DotRenderer mDotRenderer;
private DotRenderer.DrawParams mDrawParams;
private int mDotColor;
@@ -126,6 +150,39 @@
outline.setOval(inset, inset, inset + normalizedSize, inset + normalizedSize);
}
+ /**
+ * Set translation-x while this bubble is being dragged.
+ * Translation applied to the view is a sum of {@code translationX} and offset defined by
+ * {@link #setOffsetX(float)}.
+ */
+ public void setDragTranslationX(float translationX) {
+ mDragTranslationX = translationX;
+ applyDragTranslation();
+ }
+
+ /**
+ * Get translation value applied via {@link #setDragTranslationX(float)}.
+ */
+ public float getDragTranslationX() {
+ return mDragTranslationX;
+ }
+
+ /**
+ * Set offset on x-axis while dragging.
+ * Used to counter parent translation in order to keep the dragged view at the current position
+ * on screen.
+ * Translation applied to the view is a sum of {@code offsetX} and translation defined by
+ * {@link #setDragTranslationX(float)}
+ */
+ public void setOffsetX(float offsetX) {
+ mOffsetX = offsetX;
+ applyDragTranslation();
+ }
+
+ private void applyDragTranslation() {
+ setTranslationX(mDragTranslationX + mOffsetX);
+ }
+
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
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 2d8983f..d88e272 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -35,45 +35,51 @@
private val scheduler: Scheduler = HandlerScheduler(bubbleBarView)
) {
+ private var animatingBubble: AnimatingBubble? = null
+
private companion object {
/** The time to show the flyout. */
const val FLYOUT_DELAY_MS: Long = 2500
- /** The translation Y the new bubble will animate to. */
- const val BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y = -50f
- /** The initial translation Y value the new bubble is set to before the animation starts. */
- // TODO(liranb): get rid of this and calculate this based on the y-distance between the
- // bubble and the stash handle.
- const val BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET = 50f
/** The initial scale Y value that the new bubble is set to before the animation starts. */
const val BUBBLE_ANIMATION_INITIAL_SCALE_Y = 0.3f
- /**
- * The distance the stashed handle will travel as it gets hidden as part of the new bubble
- * animation.
- */
- // TODO(liranb): calculate this based on the position of the views
- const val BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y = -20f
+ /** The minimum alpha value to make the bubble bar touchable. */
+ const val MIN_ALPHA_FOR_TOUCHABLE = 0.5f
}
+ /** Wrapper around the animating bubble with its show and hide animations. */
+ private data class AnimatingBubble(
+ val bubbleView: BubbleView,
+ val showAnimation: Runnable,
+ val hideAnimation: Runnable
+ )
+
/** An interface for scheduling jobs. */
interface Scheduler {
/** Schedule the given [block] to run. */
- fun post(block: () -> Unit)
+ fun post(block: Runnable)
/** Schedule the given [block] to start with a delay of [delayMillis]. */
- fun postDelayed(delayMillis: Long, block: () -> Unit)
+ fun postDelayed(delayMillis: Long, block: Runnable)
+
+ /** Cancel the given [block] if it hasn't started yet. */
+ fun cancel(block: Runnable)
}
/** A [Scheduler] that uses a Handler to run jobs. */
private class HandlerScheduler(private val view: View) : Scheduler {
- override fun post(block: () -> Unit) {
+ override fun post(block: Runnable) {
view.post(block)
}
- override fun postDelayed(delayMillis: Long, block: () -> Unit) {
+ override fun postDelayed(delayMillis: Long, block: Runnable) {
view.postDelayed(block, delayMillis)
}
+
+ override fun cancel(block: Runnable) {
+ view.removeCallbacks(block)
+ }
}
private val springConfig =
@@ -89,163 +95,253 @@
if (animator.isRunning()) animator.cancel()
// the animation of a new bubble is divided into 2 parts. The first part shows the bubble
// and the second part hides it after a delay.
- val showAnimation = buildShowAnimation(bubbleView, b.key)
- val hideAnimation = buildHideAnimation(bubbleView)
+ val showAnimation = buildHandleToBubbleBarAnimation()
+ val hideAnimation = buildBubbleBarToHandleAnimation()
+ animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
scheduler.post(showAnimation)
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
}
/**
- * Returns a lambda that starts the animation that shows the new bubble.
+ * Returns a [Runnable] that starts the animation that morphs the handle to the bubble bar.
*
* Visually, the animation is divided into 2 parts. The stash handle starts animating up and
- * fading out and then the bubble starts animating up and fading in.
+ * fading out and then the bubble bar starts animating up and fading in.
*
- * To make the transition from the handle to the bubble smooth, the positions and movement of
- * the 2 views must be synchronized. To do that we use a single spring path along the Y axis,
- * starting from the handle's position to the eventual bubble's position. The path is split into
- * 3 parts.
+ * To make the transition from the handle to the bar smooth, the positions and movement of the 2
+ * views must be synchronized. To do that we use a single spring path along the Y axis, starting
+ * from the handle's position to the eventual bar's position. The path is split into 3 parts.
* 1. In the first part, we only animate the handle.
- * 1. In the second part the handle is fully hidden, and the bubble is animating in.
- * 1. The third part is the overshoot of the spring animation, where we make the bubble fully
+ * 2. In the second part the handle is fully hidden, and the bubble bar is animating in.
+ * 3. The third part is the overshoot of the spring animation, where we make the bubble fully
* visible which helps avoiding further updates when we re-enter the second part.
*/
- private fun buildShowAnimation(
- bubbleView: BubbleView,
- key: String,
- ): () -> Unit = {
- bubbleBarView.prepareForAnimatingBubbleWhileStashed(key)
- // calculate the initial translation x the bubble should have in order to align it with the
- // stash handle.
- val initialTranslationX =
- bubbleStashController.stashedHandleCenterX - bubbleView.centerXOnScreen
- // prepare the bubble for the animation
- bubbleView.alpha = 0f
- bubbleView.translationX = initialTranslationX
- bubbleView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
- bubbleView.visibility = VISIBLE
+ private fun buildHandleToBubbleBarAnimation() = Runnable {
+ // 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.relativePivotY = 0.5f
+
+ // this is the offset between the center of the bubble bar and the center of the stash
+ // handle. when the handle becomes invisible and we start animating in the bubble bar,
+ // the translation y is offset by this value to make the transition from the handle to the
+ // bar smooth.
+ val offset = bubbleStashController.diffBetweenHandleAndBarCenters
+ val stashedHandleTranslationY =
+ bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
// this is the total distance that both the stashed handle and the bubble will be traveling
- val totalTranslationY =
- BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+ // at the end of the animation the bubble bar will be positioned in the same place when it
+ // shows while we're in an app.
+ val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
val animator = bubbleStashController.stashedHandlePhysicsAnimator
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, totalTranslationY)
- animator.addUpdateListener { target, values ->
+ animator.addUpdateListener { handle, values ->
val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
when {
- ty >= BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y -> {
+ ty >= stashedHandleTranslationY -> {
// we're in the first leg of the animation. only animate the handle. the bubble
- // remains hidden during this part of the animation
+ // bar remains hidden during this part of the animation
- // map the path [0, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y] to [0,1]
- val fraction = ty / BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
- target.alpha = 1 - fraction / 2
+ // map the path [0, stashedHandleTranslationY] to [0,1]
+ val fraction = ty / stashedHandleTranslationY
+ handle.alpha = 1 - fraction
}
ty >= totalTranslationY -> {
// this is the second leg of the animation. the handle should be completely
- // hidden and the bubble should start animating in.
+ // hidden and the bubble bar should start animating in.
// it's possible that we're re-entering this leg because this is a spring
- // animation, so only set the alpha and scale for the bubble if we didn't
+ // animation, so only set the alpha and scale for the bubble bar if we didn't
// already fully animate in.
- target.alpha = 0f
- bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
- if (bubbleView.alpha != 1f) {
- // map the path
- // [BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y, totalTranslationY]
- // to [0, 1]
+ handle.alpha = 0f
+ bubbleBarView.translationY = ty - offset
+ if (bubbleBarView.alpha != 1f) {
+ // map the path [stashedHandleTranslationY, totalTranslationY] to [0, 1]
val fraction =
- (ty - BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y) /
- BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y
- bubbleView.alpha = fraction
- bubbleView.scaleY =
+ (ty - stashedHandleTranslationY) /
+ (totalTranslationY - stashedHandleTranslationY)
+ bubbleBarView.alpha = fraction
+ bubbleBarView.scaleY =
BUBBLE_ANIMATION_INITIAL_SCALE_Y +
(1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+ if (bubbleBarView.alpha > MIN_ALPHA_FOR_TOUCHABLE) {
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
}
}
else -> {
// we're past the target animated value, set the alpha and scale for the bubble
- // so that it's fully visible and no longer changing, but keep moving it along
- // the animation path
- bubbleView.alpha = 1f
- bubbleView.scaleY = 1f
- bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
+ // bar so that it's fully visible and no longer changing, but keep moving it
+ // along the animation path
+ bubbleBarView.alpha = 1f
+ bubbleBarView.scaleY = 1f
+ bubbleBarView.translationY = ty - offset
+ bubbleStashController.updateTaskbarTouchRegion()
}
}
}
+ animator.addEndListener { _, _, _, canceled, _, _, _ ->
+ // if the show animation was canceled, also cancel the hide animation. this is typically
+ // canceled in this class, but could potentially be canceled elsewhere.
+ if (canceled) {
+ val hideAnimation = animatingBubble?.hideAnimation ?: return@addEndListener
+ scheduler.cancel(hideAnimation)
+ animatingBubble = null
+ bubbleBarView.onAnimatingBubbleCompleted()
+ bubbleBarView.relativePivotY = 1f
+ return@addEndListener
+ }
+ // the bubble bar is now fully settled in. update taskbar touch region so it's touchable
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
animator.start()
}
/**
- * Returns a lambda that starts the animation that hides the new bubble.
+ * Returns a [Runnable] that starts the animation that hides the bubble bar and morphs it into
+ * the stashed handle.
*
* Similarly to the show animation, this is visually divided into 2 parts. We first animate the
- * bubble out, and then animate the stash handle in. At the end of the animation we reset the
- * values of the bubble.
+ * bubble bar out, and then animate the stash handle in. At the end of the animation we reset
+ * values of the bubble bar.
*
* This is a spring animation that goes along the same path of the show animation in the
* opposite order, and is split into 3 parts:
* 1. In the first part the bubble animates out.
- * 1. In the second part the bubble is fully hidden and the handle animates in.
- * 1. The third part is the overshoot. The handle is made fully visible.
+ * 2. In the second part the bubble bar is fully hidden and the handle animates in.
+ * 3. The third part is the overshoot. The handle is made fully visible.
*/
- private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = {
- // this is the total distance that both the stashed handle and the bubble will be traveling
- val totalTranslationY =
- BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+ private fun buildBubbleBarToHandleAnimation() = Runnable {
+ if (animatingBubble == null) return@Runnable
+ val offset = bubbleStashController.diffBetweenHandleAndBarCenters
+ val stashedHandleTranslationY =
+ bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
+ // this is the total distance that both the stashed handle and the bar will be traveling
+ val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
+ bubbleStashController.setHandleTranslationY(totalTranslationY)
val animator = bubbleStashController.stashedHandlePhysicsAnimator
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
- animator.addUpdateListener { target, values ->
+ animator.addUpdateListener { handle, values ->
val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
when {
- ty <= BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y -> {
- // this is the first leg of the animation. only animate the bubble. the handle
- // is hidden during this part
- bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
- // map the path
- // [totalTranslationY, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y]
- // to [0, 1]
- val fraction = (totalTranslationY - ty) / BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y
- bubbleView.alpha = 1 - fraction / 2
- bubbleView.scaleY = 1 - (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+ ty <= stashedHandleTranslationY -> {
+ // this is the first leg of the animation. only animate the bubble bar. the
+ // handle is hidden during this part
+ bubbleBarView.translationY = ty - offset
+ // map the path [totalTranslationY, stashedHandleTranslationY] to [0, 1]
+ val fraction =
+ (totalTranslationY - ty) / (totalTranslationY - stashedHandleTranslationY)
+ bubbleBarView.alpha = 1 - fraction
+ bubbleBarView.scaleY = 1 - (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+ if (bubbleBarView.alpha > MIN_ALPHA_FOR_TOUCHABLE) {
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
}
ty <= 0 -> {
- // this is the second part of the animation. make the bubble invisible and
+ // this is the second part of the animation. make the bubble bar invisible and
// start fading in the handle, but don't update the alpha if it's already fully
// visible
- bubbleView.alpha = 0f
- if (target.alpha != 1f) {
- // map the path [BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y, 0] to [0, 1]
- val fraction =
- (BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y - ty) /
- BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
- target.alpha = fraction
+ bubbleBarView.alpha = 0f
+ if (handle.alpha != 1f) {
+ // map the path [stashedHandleTranslationY, 0] to [0, 1]
+ val fraction = (stashedHandleTranslationY - ty) / stashedHandleTranslationY
+ handle.alpha = fraction
}
}
else -> {
// we reached the target value. set the alpha of the handle to 1
- target.alpha = 1f
+ handle.alpha = 1f
}
}
}
- animator.addEndListener { _, _, _, _, _, _, _ ->
- bubbleView.alpha = 0f
- bubbleView.translationY = 0f
- bubbleView.scaleY = 1f
- if (bubbleStashController.isStashed) {
- bubbleBarView.alpha = 0f
- }
+ animator.addEndListener { _, _, _, canceled, _, _, _ ->
+ animatingBubble = null
+ if (!canceled) bubbleStashController.stashBubbleBarImmediate()
bubbleBarView.onAnimatingBubbleCompleted()
+ bubbleBarView.relativePivotY = 1f
+ bubbleStashController.updateTaskbarTouchRegion()
}
animator.start()
}
-}
-/** The X position in screen coordinates of the center of the bubble. */
-private val BubbleView.centerXOnScreen: Float
- get() {
- val screenCoordinates = IntArray(2)
- getLocationOnScreen(screenCoordinates)
- return screenCoordinates[0] + width / 2f
+ /** Animates to the initial state of the bubble bar, when there are no previous bubbles. */
+ fun animateToInitialState(b: BubbleBarBubble, isInApp: Boolean, isExpanding: Boolean) {
+ val bubbleView = b.view
+ val animator = PhysicsAnimator.getInstance(bubbleView)
+ if (animator.isRunning()) animator.cancel()
+ // the animation of a new bubble is divided into 2 parts. The first part shows the bubble
+ // and the second part hides it after a delay if we are in an app.
+ val showAnimation = buildBubbleBarBounceAnimation()
+ val hideAnimation =
+ if (isInApp && !isExpanding) {
+ buildBubbleBarToHandleAnimation()
+ } else {
+ // in this case the bubble bar remains visible so not much to do. once we implement
+ // the flyout we'll update this runnable to hide it.
+ Runnable {
+ animatingBubble = null
+ bubbleStashController.showBubbleBarImmediate()
+ bubbleBarView.onAnimatingBubbleCompleted()
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
+ }
+ animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+ scheduler.post(showAnimation)
+ scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
}
+
+ private fun buildBubbleBarBounceAnimation() = Runnable {
+ // prepare the bubble bar for the animation
+ bubbleBarView.onAnimatingBubbleStarted()
+ bubbleBarView.translationY = bubbleBarView.height.toFloat()
+ bubbleBarView.visibility = VISIBLE
+ bubbleBarView.alpha = 1f
+ bubbleBarView.scaleX = 1f
+ bubbleBarView.scaleY = 1f
+
+ val animator = PhysicsAnimator.getInstance(bubbleBarView)
+ animator.setDefaultSpringConfig(springConfig)
+ animator.spring(DynamicAnimation.TRANSLATION_Y, bubbleStashController.bubbleBarTranslationY)
+ animator.addUpdateListener { _, _ -> bubbleStashController.updateTaskbarTouchRegion() }
+ animator.addEndListener { _, _, _, _, _, _, _ ->
+ // the bubble bar is now fully settled in. update taskbar touch region so it's touchable
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
+ animator.start()
+ }
+
+ /** Handles touching the animating bubble bar. */
+ fun onBubbleBarTouchedWhileAnimating() {
+ PhysicsAnimator.getInstance(bubbleBarView).cancelIfRunning()
+ bubbleStashController.stashedHandlePhysicsAnimator.cancelIfRunning()
+ val hideAnimation = animatingBubble?.hideAnimation ?: return
+ scheduler.cancel(hideAnimation)
+ bubbleBarView.onAnimatingBubbleCompleted()
+ bubbleBarView.relativePivotY = 1f
+ animatingBubble = null
+ }
+
+ /** Notifies the animator that the taskbar area was touched during an animation. */
+ fun onStashStateChangingWhileAnimating() {
+ val hideAnimation = animatingBubble?.hideAnimation ?: return
+ scheduler.cancel(hideAnimation)
+ animatingBubble = null
+ bubbleStashController.stashedHandlePhysicsAnimator.cancel()
+ bubbleBarView.onAnimatingBubbleCompleted()
+ bubbleBarView.relativePivotY = 1f
+ bubbleStashController.onNewBubbleAnimationInterrupted(
+ /* isStashed= */ bubbleBarView.alpha == 0f,
+ bubbleBarView.translationY
+ )
+ }
+
+ private fun <T> PhysicsAnimator<T>.cancelIfRunning() {
+ if (isRunning()) cancel()
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index fe91362..e487f9f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -24,10 +24,11 @@
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Space
+import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.Utilities
+import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
-import com.android.systemui.shared.rotation.RotationButton
/**
* Meant to be a simple container for data subclasses will need
@@ -41,14 +42,13 @@
* @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
*/
abstract class AbstractNavButtonLayoutter(
- val resources: Resources,
- val navButtonContainer: LinearLayout,
- protected val endContextualContainer: ViewGroup,
- protected val startContextualContainer: ViewGroup,
- protected val imeSwitcher: ImageView?,
- protected val rotationButton: RotationButton?,
- protected val a11yButton: ImageView?,
- protected val space: Space?
+ val resources: Resources,
+ val navButtonContainer: LinearLayout,
+ protected val endContextualContainer: ViewGroup,
+ protected val startContextualContainer: ViewGroup,
+ protected val imeSwitcher: ImageView?,
+ protected val a11yButton: ImageView?,
+ protected val space: Space?
) : NavButtonLayoutter {
protected val homeButton: ImageView? = navButtonContainer.findViewById(R.id.home)
protected val recentsButton: ImageView? = navButtonContainer.findViewById(R.id.recent_apps)
@@ -66,17 +66,41 @@
}
fun getParamsToCenterView(): FrameLayout.LayoutParams {
- val params = FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ val params =
+ FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
params.gravity = Gravity.CENTER
- return params;
+ return params
}
- open fun repositionContextualContainer(contextualContainer: ViewGroup, buttonSize: Int,
- barAxisMarginStart: Int, barAxisMarginEnd: Int,
- gravity: Int) {
- val contextualContainerParams = FrameLayout.LayoutParams(
- buttonSize, ViewGroup.LayoutParams.MATCH_PARENT)
+ fun adjustForSetupInPhoneMode(
+ navButtonsLayoutParams: FrameLayout.LayoutParams,
+ navButtonsViewLayoutParams: FrameLayout.LayoutParams,
+ deviceProfile: DeviceProfile
+ ) {
+ val phoneOrPortraitSetupMargin =
+ resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_margin)
+ navButtonsLayoutParams.marginStart = phoneOrPortraitSetupMargin
+ navButtonsLayoutParams.bottomMargin =
+ if (!deviceProfile.isLandscape) 0
+ else
+ phoneOrPortraitSetupMargin -
+ resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2
+ navButtonsViewLayoutParams.height =
+ resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_height)
+ }
+
+ open fun repositionContextualContainer(
+ contextualContainer: ViewGroup,
+ buttonSize: Int,
+ barAxisMarginStart: Int,
+ barAxisMarginEnd: Int,
+ gravity: Int
+ ) {
+ val contextualContainerParams =
+ FrameLayout.LayoutParams(buttonSize, ViewGroup.LayoutParams.MATCH_PARENT)
contextualContainerParams.apply {
marginStart = barAxisMarginStart
marginEnd = barAxisMarginEnd
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
index 4368b95..aa8f5a3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
@@ -29,27 +29,24 @@
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
-import com.android.systemui.shared.rotation.RotationButton
class KidsNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup,
- imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
- a11yButton: ImageView?,
- space: Space?
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ a11yButton: ImageView?,
+ space: Space?
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer,
- imeSwitcher,
- rotationButton,
- a11yButton,
- space
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ a11yButton,
+ space
) {
override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
@@ -105,11 +102,16 @@
endContextualContainer.removeAllViews()
startContextualContainer.removeAllViews()
- val contextualMargin = resources.getDimensionPixelSize(
- R.dimen.taskbar_contextual_button_padding)
+ val contextualMargin =
+ resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_padding)
repositionContextualContainer(endContextualContainer, WRAP_CONTENT, 0, 0, Gravity.END)
- repositionContextualContainer(startContextualContainer, WRAP_CONTENT, contextualMargin,
- contextualMargin, Gravity.START)
+ repositionContextualContainer(
+ startContextualContainer,
+ WRAP_CONTENT,
+ contextualMargin,
+ contextualMargin,
+ Gravity.START
+ )
if (imeSwitcher != null) {
startContextualContainer.addView(imeSwitcher)
@@ -119,9 +121,5 @@
endContextualContainer.addView(a11yButton)
a11yButton.layoutParams = getParamsToCenterView()
}
- if (rotationButton != null) {
- endContextualContainer.addView(rotationButton.currentView)
- rotationButton.currentView.layoutParams = getParamsToCenterView()
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index 5bfdce9..2497fbb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -25,10 +25,11 @@
import android.widget.Space
import com.android.launcher3.DeviceProfile
import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.Companion
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
-import com.android.systemui.shared.rotation.RotationButton
/**
* Select the correct layout for nav buttons
@@ -58,7 +59,6 @@
deviceProfile: DeviceProfile,
navButtonsView: NearestTouchFrame,
imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
a11yButton: ImageView?,
space: Space?,
resources: Resources,
@@ -86,7 +86,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
)
@@ -98,7 +97,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
)
@@ -110,7 +108,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
)
@@ -119,11 +116,11 @@
isPhoneGestureMode -> {
PhoneGestureLayoutter(
resources,
+ navButtonsView,
navButtonContainer,
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
)
@@ -138,7 +135,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
)
@@ -150,7 +146,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
)
@@ -162,7 +157,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
)
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
index bf820c0..390ec34 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
@@ -17,36 +17,60 @@
package com.android.launcher3.taskbar.navbutton
import android.content.res.Resources
+import android.view.Gravity
import android.view.ViewGroup
+import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Space
+import com.android.launcher3.DeviceProfile
import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
/** Layoutter for showing gesture navigation on phone screen. No buttons here, no-op container */
class PhoneGestureLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup,
- imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
- a11yButton: ImageView?,
- space: Space?
+ resources: Resources,
+ navButtonsView: NearestTouchFrame,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ a11yButton: ImageView?,
+ space: Space?
) :
- AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer,
- imeSwitcher,
- rotationButton,
- a11yButton,
- space
- ) {
+ AbstractNavButtonLayoutter(
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ a11yButton,
+ space
+ ) {
+ private val mNavButtonsView = navButtonsView
override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
+ // TODO: look into if we should use SetupNavLayoutter instead.
+ if (!context.isUserSetupComplete) {
+ // Since setup wizard only has back button enabled, it looks strange to be
+ // end-aligned, so start-align instead.
+ val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
+ val navButtonsViewLayoutParams =
+ mNavButtonsView.layoutParams as FrameLayout.LayoutParams
+ val deviceProfile: DeviceProfile = context.deviceProfile
+
+ navButtonsLayoutParams.marginEnd = 0
+ navButtonsLayoutParams.gravity = Gravity.START
+ context.setTaskbarWindowSize(context.setupWindowSize)
+
+ adjustForSetupInPhoneMode(
+ navButtonsLayoutParams,
+ navButtonsViewLayoutParams,
+ deviceProfile
+ )
+ mNavButtonsView.layoutParams = navButtonsViewLayoutParams
+ navButtonContainer.layoutParams = navButtonsLayoutParams
+ }
+
endContextualContainer.removeAllViews()
startContextualContainer.removeAllViews()
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
index 6a935f1..9f7f07e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
@@ -26,35 +26,32 @@
import android.widget.Space
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
open class PhoneLandscapeNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup,
- imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
- a11yButton: ImageView?,
- space: Space?
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ a11yButton: ImageView?,
+ space: Space?
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer,
- imeSwitcher,
- rotationButton,
- a11yButton,
- space
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ a11yButton,
+ space
) {
override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
val totalHeight = context.deviceProfile.heightPx
- val homeButtonHeight = resources.getDimensionPixelSize(
- R.dimen.taskbar_phone_home_button_size)
- val roundedCornerContentMargin = resources.getDimensionPixelSize(
- R.dimen.taskbar_phone_rounded_corner_content_margin)
+ val homeButtonHeight =
+ resources.getDimensionPixelSize(R.dimen.taskbar_phone_home_button_size)
+ val roundedCornerContentMargin =
+ resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
val contentWidth = totalHeight - roundedCornerContentMargin * 2 - contentPadding * 2
@@ -63,13 +60,13 @@
val sideButtonHeight = contextualButtonHeight * 2
val navButtonContainerHeight = contentWidth - contextualButtonHeight * 2
- val navContainerParams = FrameLayout.LayoutParams(
- MATCH_PARENT, navButtonContainerHeight.toInt())
+ val navContainerParams =
+ FrameLayout.LayoutParams(MATCH_PARENT, navButtonContainerHeight.toInt())
navContainerParams.apply {
topMargin =
- (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
+ (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
bottomMargin =
- (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
+ (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
marginEnd = 0
marginStart = 0
}
@@ -84,8 +81,8 @@
navButtonContainer.gravity = Gravity.CENTER
// Add the spaces in between the nav buttons
- val spaceInBetween = (navButtonContainerHeight - homeButtonHeight -
- sideButtonHeight * 2) / 2.0f
+ val spaceInBetween =
+ (navButtonContainerHeight - homeButtonHeight - sideButtonHeight * 2) / 2.0f
for (i in 0 until navButtonContainer.childCount) {
val navButton = navButtonContainer.getChildAt(i)
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
@@ -124,13 +121,23 @@
endContextualContainer.removeAllViews()
startContextualContainer.removeAllViews()
- val roundedCornerContentMargin = resources.getDimensionPixelSize(
- R.dimen.taskbar_phone_rounded_corner_content_margin)
+ val roundedCornerContentMargin =
+ resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
- repositionContextualContainer(startContextualContainer, buttonSize,
- roundedCornerContentMargin + contentPadding, 0, Gravity.TOP)
- repositionContextualContainer(endContextualContainer, buttonSize,
- 0, roundedCornerContentMargin + contentPadding, Gravity.BOTTOM)
+ repositionContextualContainer(
+ startContextualContainer,
+ buttonSize,
+ roundedCornerContentMargin + contentPadding,
+ 0,
+ Gravity.TOP
+ )
+ repositionContextualContainer(
+ endContextualContainer,
+ buttonSize,
+ 0,
+ roundedCornerContentMargin + contentPadding,
+ Gravity.BOTTOM
+ )
if (imeSwitcher != null) {
startContextualContainer.addView(imeSwitcher)
@@ -140,16 +147,16 @@
startContextualContainer.addView(a11yButton)
a11yButton.layoutParams = getParamsToCenterView()
}
- if (rotationButton != null) {
- startContextualContainer.addView(rotationButton.currentView)
- rotationButton.currentView.layoutParams = getParamsToCenterView()
- }
endContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
}
- override fun repositionContextualContainer(contextualContainer: ViewGroup, buttonSize: Int,
- barAxisMarginTop: Int, barAxisMarginBottom: Int,
- gravity: Int) {
+ override fun repositionContextualContainer(
+ contextualContainer: ViewGroup,
+ buttonSize: Int,
+ barAxisMarginTop: Int,
+ barAxisMarginBottom: Int,
+ gravity: Int
+ ) {
val contextualContainerParams = FrameLayout.LayoutParams(MATCH_PARENT, buttonSize)
contextualContainerParams.apply {
marginStart = 0
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
index 0672270..5b24ebf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
@@ -26,34 +26,32 @@
import android.widget.Space
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
class PhonePortraitNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup,
- imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
- a11yButton: ImageView?,
- space: Space?
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ a11yButton: ImageView?,
+ space: Space?
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer,
- imeSwitcher,
- rotationButton,
- a11yButton,
- space
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ a11yButton,
+ space
) {
override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
val totalWidth = context.deviceProfile.widthPx
- val homeButtonWidth = resources.getDimensionPixelSize(R.dimen.taskbar_phone_home_button_size)
- val roundedCornerContentMargin = resources.getDimensionPixelSize(
- R.dimen.taskbar_phone_rounded_corner_content_margin)
+ val homeButtonWidth =
+ resources.getDimensionPixelSize(R.dimen.taskbar_phone_home_button_size)
+ val roundedCornerContentMargin =
+ resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
val contentWidth = totalWidth - roundedCornerContentMargin * 2 - contentPadding * 2
@@ -62,15 +60,18 @@
val sideButtonWidth = contextualButtonWidth * 2
val navButtonContainerWidth = contentWidth - contextualButtonWidth * 2
- val navContainerParams = FrameLayout.LayoutParams(navButtonContainerWidth.toInt(),
- ViewGroup.LayoutParams.MATCH_PARENT)
+ val navContainerParams =
+ FrameLayout.LayoutParams(
+ navButtonContainerWidth.toInt(),
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
navContainerParams.apply {
topMargin = 0
bottomMargin = 0
marginEnd =
- (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
+ (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
marginStart =
- (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
+ (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
}
// Ensure order of buttons is correct
@@ -85,8 +86,8 @@
navButtonContainer.gravity = Gravity.CENTER
// Add the spaces in between the nav buttons
- val spaceInBetween = (navButtonContainerWidth - homeButtonWidth -
- sideButtonWidth * 2) / 2.0f
+ val spaceInBetween =
+ (navButtonContainerWidth - homeButtonWidth - sideButtonWidth * 2) / 2.0f
for (i in 0 until navButtonContainer.childCount) {
val navButton = navButtonContainer.getChildAt(i)
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
@@ -114,10 +115,20 @@
endContextualContainer.removeAllViews()
startContextualContainer.removeAllViews()
- repositionContextualContainer(startContextualContainer, contextualButtonWidth.toInt(),
- roundedCornerContentMargin + contentPadding, 0, Gravity.START)
- repositionContextualContainer(endContextualContainer, contextualButtonWidth.toInt(), 0,
- roundedCornerContentMargin + contentPadding, Gravity.END)
+ repositionContextualContainer(
+ startContextualContainer,
+ contextualButtonWidth.toInt(),
+ roundedCornerContentMargin + contentPadding,
+ 0,
+ Gravity.START
+ )
+ repositionContextualContainer(
+ endContextualContainer,
+ contextualButtonWidth.toInt(),
+ 0,
+ roundedCornerContentMargin + contentPadding,
+ Gravity.END
+ )
startContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
if (imeSwitcher != null) {
@@ -128,9 +139,5 @@
endContextualContainer.addView(a11yButton)
a11yButton.layoutParams = getParamsToCenterView()
}
- if (rotationButton != null) {
- endContextualContainer.addView(rotationButton.currentView)
- rotationButton.currentView.layoutParams = getParamsToCenterView()
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
index 869cc43..f0b47f4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
@@ -1,18 +1,18 @@
/*
-* 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
-*/
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
package com.android.launcher3.taskbar.navbutton
@@ -24,28 +24,25 @@
import android.widget.LinearLayout
import android.widget.Space
import com.android.launcher3.R
-import com.android.systemui.shared.rotation.RotationButton
class PhoneSeascapeNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup,
- imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
- a11yButton: ImageView?,
- space: Space?
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ a11yButton: ImageView?,
+ space: Space?
) :
- PhoneLandscapeNavLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer,
- imeSwitcher,
- rotationButton,
- a11yButton,
- space
- ) {
+ PhoneLandscapeNavLayoutter(
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ a11yButton,
+ space
+ ) {
override fun addThreeButtons() {
// Flip ordering of back and recents buttons
@@ -58,13 +55,23 @@
endContextualContainer.removeAllViews()
startContextualContainer.removeAllViews()
- val roundedCornerContentMargin = resources.getDimensionPixelSize(
- R.dimen.taskbar_phone_rounded_corner_content_margin)
+ val roundedCornerContentMargin =
+ resources.getDimensionPixelSize(R.dimen.taskbar_phone_rounded_corner_content_margin)
val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
- repositionContextualContainer(startContextualContainer, buttonSize,
- roundedCornerContentMargin + contentPadding, 0, Gravity.TOP)
- repositionContextualContainer(endContextualContainer, buttonSize, 0,
- roundedCornerContentMargin + contentPadding, Gravity.BOTTOM)
+ repositionContextualContainer(
+ startContextualContainer,
+ buttonSize,
+ roundedCornerContentMargin + contentPadding,
+ 0,
+ Gravity.TOP
+ )
+ repositionContextualContainer(
+ endContextualContainer,
+ buttonSize,
+ 0,
+ roundedCornerContentMargin + contentPadding,
+ Gravity.BOTTOM
+ )
startContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
if (imeSwitcher != null) {
@@ -75,9 +82,5 @@
endContextualContainer.addView(a11yButton)
a11yButton.layoutParams = getParamsToCenterView()
}
- if (rotationButton != null) {
- endContextualContainer.addView(rotationButton.currentView)
- rotationButton.currentView.layoutParams = getParamsToCenterView()
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
index 8eff95c..22a3630 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
@@ -27,7 +27,6 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
const val SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95
const val SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05
@@ -39,7 +38,6 @@
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup,
imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
a11yButton: ImageView?,
space: Space?
) :
@@ -49,7 +47,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
) {
@@ -80,16 +77,11 @@
navButtonsLayoutParams.height =
resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_height)
} else {
- val phoneOrPortraitSetupMargin =
- resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_margin)
- navButtonsLayoutParams.marginStart = phoneOrPortraitSetupMargin
- navButtonsLayoutParams.bottomMargin =
- if (!deviceProfile.isLandscape) 0
- else
- phoneOrPortraitSetupMargin -
- resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2
- navButtonsViewLayoutParams.height =
- resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_height)
+ adjustForSetupInPhoneMode(
+ navButtonsLayoutParams,
+ navButtonsViewLayoutParams,
+ deviceProfile
+ )
}
mNavButtonsView.layoutParams = navButtonsViewLayoutParams
navButtonContainer.layoutParams = navButtonsLayoutParams
@@ -116,9 +108,5 @@
endContextualContainer.addView(a11yButton)
a11yButton.layoutParams = getParamsToCenterView()
}
- if (rotationButton != null) {
- endContextualContainer.addView(rotationButton.currentView)
- rotationButton.currentView.layoutParams = getParamsToCenterView()
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
index 34d3fad..a59e8a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
@@ -26,7 +26,6 @@
import android.widget.Space
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.systemui.shared.rotation.RotationButton
/** Layoutter for rendering task bar in large screen, both in 3-button and gesture nav mode. */
class TaskbarNavLayoutter(
@@ -35,7 +34,6 @@
endContextualContainer: ViewGroup,
startContextualContainer: ViewGroup,
imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
a11yButton: ImageView?,
space: Space?
) :
@@ -45,7 +43,6 @@
endContextualContainer,
startContextualContainer,
imeSwitcher,
- rotationButton,
a11yButton,
space
) {
@@ -137,10 +134,6 @@
endContextualContainer.addView(a11yButton)
a11yButton.layoutParams = getParamsToCenterView()
}
- if (rotationButton != null) {
- endContextualContainer.addView(rotationButton.currentView)
- rotationButton.currentView.layoutParams = getParamsToCenterView()
- }
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 4acddee..b1bb198 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -166,6 +166,8 @@
import com.android.launcher3.util.TouchController;
import com.android.launcher3.widget.LauncherWidgetHolder;
import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
@@ -264,6 +266,10 @@
getDepthController(), getStatsLogManager(),
systemUiProxy, RecentsModel.INSTANCE.get(this),
() -> onStateBack());
+ RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(asContext());
+ // TODO(b/337863494): Explore use of the same OverviewComponentObserver across launcher
+ OverviewComponentObserver overviewComponentObserver = new OverviewComponentObserver(
+ asContext(), deviceState);
if (enableDesktopWindowingMode()) {
mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
getStateManager(), systemUiProxy, getIApplicationThread(),
@@ -272,7 +278,7 @@
overviewPanel.init(mActionsView, mSplitSelectStateController,
mDesktopRecentsTransitionController);
mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this,
- mSplitSelectStateController);
+ mSplitSelectStateController, overviewComponentObserver, deviceState);
mSplitToWorkspaceController = new SplitToWorkspaceController(this,
mSplitSelectStateController);
mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
@@ -287,7 +293,8 @@
if (enableDesktopWindowingMode()) {
mDesktopVisibilityController = new DesktopVisibilityController(this);
mDesktopVisibilityController.registerSystemUiListener();
- mSplitSelectStateController.initSplitFromDesktopController(this);
+ mSplitSelectStateController.initSplitFromDesktopController(this,
+ overviewComponentObserver);
}
mHotseatPredictionController = new HotseatPredictionController(this);
@@ -391,6 +398,12 @@
}
@Override
+ public void startBinding() {
+ super.startBinding();
+ mHotseatPredictionController.verifyUIUpdateNotPaused();
+ }
+
+ @Override
protected void onActivityFlagsChanged(int changeBits) {
if ((changeBits & ACTIVITY_STATE_STARTED) != 0) {
mDepthController.setActivityStarted(isStarted());
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 6c1d4b1..e02ec41 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
-import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
@@ -41,6 +40,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
@@ -168,7 +168,7 @@
clearAllButtonAlpha, LINEAR);
float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
- MULTI_PROPERTY_VALUE, overviewButtonAlpha, config.getInterpolator(
+ AnimatedFloat.VALUE, overviewButtonAlpha, config.getInterpolator(
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 527a776..7e0a10f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -248,7 +248,7 @@
TASK_THUMBNAIL_SPLASH_ALPHA.set(mRecentsView, fromState.showTaskThumbnailSplash() ? 1f : 0);
mRecentsView.setContentAlpha(1);
mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
- mLauncher.getActionsView().getVisibilityAlpha().setValue(
+ mLauncher.getActionsView().getVisibilityAlpha().updateValue(
(fromState.getVisibleElements(mLauncher) & OVERVIEW_ACTIONS) != 0 ? 1f : 0f);
mRecentsView.setTaskIconScaledDown(true);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 05a55d0..16185f5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -151,7 +151,7 @@
int sysuiFlags = 0;
TaskView tv = mOverviewPanel.getTaskViewAt(0);
if (tv != null) {
- sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+ sysuiFlags = tv.getFirstThumbnailView().getSysUiStatusNavFlags();
}
mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, sysuiFlags);
} else {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 300d697..26b528c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -252,7 +252,7 @@
mTaskBeingDragged, maxDuration, currentInterpolator);
// Since the thumbnail is what is filling the screen, based the end displacement on it.
- View thumbnailView = mTaskBeingDragged.getThumbnail();
+ View thumbnailView = mTaskBeingDragged.getFirstThumbnailView();
mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView);
dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords);
mEndDisplacement = secondaryLayerDimension - mTempCords[1];
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9e1addf..28ae3d2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.BaseActivity.EVENT_STARTED;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.PagedView.INVALID_PAGE;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -38,8 +39,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
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.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -136,10 +135,11 @@
import com.android.quickstep.util.SwipePipToHomeAnimator;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -148,12 +148,14 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.window.flags.Flags;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.startingsurface.SplashScreenExitAnimationUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
@@ -922,7 +924,7 @@
TaskView runningTask = mRecentsView.getRunningTaskView();
TaskView centermostTask = mRecentsView.getTaskViewNearestToCenterOfScreen();
int centermostTaskFlags = centermostTask == null ? 0
- : centermostTask.getThumbnail().getSysUiStatusNavFlags();
+ : centermostTask.getFirstThumbnailView().getSysUiStatusNavFlags();
boolean swipeUpThresholdPassed = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
boolean quickswitchThresholdPassed = centermostTask != runningTask;
@@ -1258,13 +1260,16 @@
? mRecentsView.getNextPageTaskView() : null;
TaskView currentPageTaskView = mRecentsView != null
? mRecentsView.getCurrentPageTaskView() : null;
- if (((nextPageTaskView != null && nextPageTaskView.isDesktopTask())
- || (currentPageTaskView != null && currentPageTaskView.isDesktopTask()))
- && endTarget == NEW_TASK) {
- // TODO(b/268075592): add support for quickswitch to/from desktop
- return LAST_TASK;
- }
+ if (Flags.enableDesktopWindowingMode()
+ && !(Flags.enableDesktopWindowingWallpaperActivity()
+ && Flags.enableDesktopWindowingQuickSwitch())) {
+ if ((nextPageTaskView instanceof DesktopTaskView
+ || currentPageTaskView instanceof DesktopTaskView)
+ && endTarget == NEW_TASK) {
+ return LAST_TASK;
+ }
+ }
return endTarget;
}
@@ -1421,14 +1426,27 @@
mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
setClampScrollOffset(false);
};
- if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
- && !mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
- ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
- .SET_ON_PAGE_TRANSITION_END_CALLBACK);
- // TODO(b/268075592): add support for quickswitch to/from desktop
- mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+
+ if (Flags.enableDesktopWindowingMode()
+ && !(Flags.enableDesktopWindowingWallpaperActivity()
+ && Flags.enableDesktopWindowingQuickSwitch())) {
+ if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
+ && !(mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView))) {
+ ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
+ .SET_ON_PAGE_TRANSITION_END_CALLBACK);
+ mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+ } else {
+ onPageTransitionEnd.run();
+ }
} else {
- onPageTransitionEnd.run();
+ if (mRecentsView != null) {
+ ActiveGestureLog.INSTANCE.trackEvent(
+ ActiveGestureErrorDetector
+ .GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK);
+ mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+ } else {
+ onPageTransitionEnd.run();
+ }
}
animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
@@ -1482,8 +1500,12 @@
}
protected abstract HomeAnimationFactory createHomeAnimationFactory(
- ArrayList<IBinder> launchCookies, long duration, boolean isTargetTranslucent,
- boolean appCanEnterPip, RemoteAnimationTarget runningTaskTarget);
+ List<IBinder> launchCookies,
+ long duration,
+ boolean isTargetTranslucent,
+ boolean appCanEnterPip,
+ RemoteAnimationTarget runningTaskTarget,
+ @Nullable TaskView targetTaskView);
private final TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
@Override
@@ -1557,9 +1579,16 @@
&& runningTaskTarget.allowEnterPip
&& runningTaskTarget.taskInfo.pictureInPictureParams != null
&& runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled();
- HomeAnimationFactory homeAnimFactory =
- createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
- runningTaskTarget);
+ HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(
+ cookies,
+ duration,
+ isTranslucent,
+ appCanEnterPip,
+ runningTaskTarget,
+ !enableAdditionalHomeAnimations()
+ || mRecentsView == null
+ || mRecentsView.getCurrentPage() == mRecentsView.getRunningTaskIndex()
+ ? null : mRecentsView.getCurrentPageTaskView());
SwipePipToHomeAnimator swipePipToHomeAnimator = !mIsSwipeForSplit && appCanEnterPip
? createWindowAnimationToPip(homeAnimFactory, runningTaskTarget, start)
: null;
@@ -1651,12 +1680,6 @@
int taskToLaunch = mRecentsView.getNextPage();
int runningTask = getLastAppearedTaskIndex();
boolean hasStartedNewTask = hasStartedNewTask();
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "taskToLaunch=" + taskToLaunch);
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "runningTask=" + runningTask);
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "hasStartedNewTask=" + hasStartedNewTask);
if (target == NEW_TASK && taskToLaunch == runningTask
&& !hasStartedNewTask) {
// We are about to launch the current running task, so use LAST_TASK
@@ -2245,13 +2268,14 @@
mRecentsAnimationController, mRecentsAnimationTargets);
});
- if ((mRecentsView.getNextPageTaskView() != null
- && mRecentsView.getNextPageTaskView().isDesktopTask())
- || (mRecentsView.getCurrentPageTaskView() != null
- && mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
- // TODO(b/268075592): add support for quickswitch to/from desktop
- mRecentsViewScrollLinked = false;
- return;
+ if (Flags.enableDesktopWindowingMode()
+ && !(Flags.enableDesktopWindowingWallpaperActivity()
+ && Flags.enableDesktopWindowingQuickSwitch())) {
+ if (mRecentsView.getNextPageTaskView() instanceof DesktopTaskView
+ || mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView) {
+ mRecentsViewScrollLinked = false;
+ return;
+ }
}
// Disable scrolling in RecentsView for trackpad 3-finger swipe up gesture.
@@ -2282,15 +2306,15 @@
int[] taskIds = nextTask.getTaskIds();
ActiveGestureLog.CompoundString nextTaskLog = new ActiveGestureLog.CompoundString(
"Launching task: ");
- for (TaskIdAttributeContainer c : nextTask.getTaskIdAttributeContainers()) {
- if (c == null) {
+ for (TaskContainer container : nextTask.getTaskContainers()) {
+ if (container == null) {
continue;
}
nextTaskLog
.append("[id: ")
- .append(c.getTask().key.id)
+ .append(container.getTask().key.id)
.append(", pkg: ")
- .append(c.getTask().key.getPackageName())
+ .append(container.getTask().key.getPackageName())
.append("] | ");
}
mGestureState.updateLastStartedTaskIds(taskIds);
@@ -2402,7 +2426,7 @@
RemoteAnimationTarget taskTarget = taskTargetOptional.get();
TaskView taskView = mRecentsView == null
? null : mRecentsView.getTaskViewByTaskId(taskTarget.taskId);
- if (taskView == null || !taskView.getThumbnail().shouldShowSplashView()) {
+ if (taskView == null || !taskView.getFirstThumbnailView().shouldShowSplashView()) {
ActiveGestureLog.INSTANCE.addLog("Invalid task view splash state");
finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
return;
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index f26d594..e33ef7f 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -23,12 +23,12 @@
import com.android.launcher3.popup.SystemShortcut
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
class DesktopSystemShortcut(
container: RecentsViewContainer,
- private val mTaskContainer: TaskIdAttributeContainer,
+ private val mTaskContainer: TaskContainer,
abstractFloatingViewHelper: AbstractFloatingViewHelper
) :
SystemShortcut<RecentsViewContainer>(
@@ -59,7 +59,7 @@
return object : TaskShortcutFactory {
override fun getShortcuts(
container: RecentsViewContainer,
- taskContainer: TaskIdAttributeContainer
+ taskContainer: TaskContainer
): List<DesktopSystemShortcut>? {
return if (!DesktopModeStatus.canEnterDesktopMode(container.asContext())) null
else if (!taskContainer.task.isDockable) null
@@ -73,7 +73,7 @@
)
}
- override fun showForSplitscreen() = true
+ override fun showForGroupedTask() = true
}
}
}
diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
index f68f793..0f844e1 100644
--- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
+++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
@@ -154,7 +154,7 @@
}
companion object {
- val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
+ @JvmStatic val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
@JvmStatic fun get() = configHelper.config
}
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 92cdf72..625b6c6 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -68,11 +68,12 @@
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
+import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.system.InputConsumerController;
import java.lang.ref.WeakReference;
-import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
@@ -140,9 +141,13 @@
}
@Override
- protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies,
- long duration, boolean isTargetTranslucent, boolean appCanEnterPip,
- RemoteAnimationTarget runningTaskTarget) {
+ protected HomeAnimationFactory createHomeAnimationFactory(
+ List<IBinder> launchCookies,
+ long duration,
+ boolean isTargetTranslucent,
+ boolean appCanEnterPip,
+ RemoteAnimationTarget runningTaskTarget,
+ @Nullable TaskView targetTaskView) {
mAppCanEnterPip = appCanEnterPip;
if (appCanEnterPip) {
return new FallbackPipToHomeAnimationFactory();
@@ -380,7 +385,7 @@
}
@Override
- public void update(RectF currentRect, float progress, float radius) {
+ public void update(RectF currentRect, float progress, float radius, int overlayAlpha) {
if (mSurfaceControl != null) {
currentRect.roundOut(mTempRect);
Transaction t = new Transaction();
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index c8a91df..81c9d4a 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -186,6 +186,7 @@
private final long mSwipeUpStartTimeMs = SystemClock.uptimeMillis();
private boolean mHandlingAtomicEvent;
+ private boolean mIsInExtendedSlopRegion;
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
mHomeIntent = componentObserver.getHomeIntent();
@@ -494,6 +495,25 @@
}
/**
+ * Set whether it's in long press nav handle (LPNH)'s extended touch slop region, e.g., second
+ * stage region in order to continue respect LPNH and ignore other touch slop logic.
+ * This will only be set to true when flag ENABLE_LPNH_TWO_STAGES is turned on.
+ */
+ public void setIsInExtendedSlopRegion(boolean isInExtendedSlopRegion) {
+ if (DeviceConfigWrapper.get().getEnableLpnhTwoStages()) {
+ mIsInExtendedSlopRegion = isInExtendedSlopRegion;
+ }
+ }
+
+ /**
+ * Returns whether it's in LPNH's extended touch slop region. This is only valid when flag
+ * ENABLE_LPNH_TWO_STAGES is turned on.
+ */
+ public boolean isInExtendedSlopRegion() {
+ return mIsInExtendedSlopRegion;
+ }
+
+ /**
* Returns and clears the canceled animation thumbnail data. This call only returns a value
* while STATE_RECENTS_ANIMATION_CANCELED state is being set, and the caller is responsible for
* calling {@link RecentsAnimationController#cleanupScreenshot()}.
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 79b09fd..225b127 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -220,6 +220,11 @@
}
});
}
+
+ @Override
+ public void setTriggerBack(boolean triggerBack) {
+ // TODO(b/261654570): track touch from the Launcher process.
+ }
}
private static class RemoteAnimationRunnerStub extends IRemoteAnimationRunner.Stub {
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index af02ccf..6a9f509 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -43,6 +43,7 @@
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ObjectWrapper;
+import com.android.launcher3.views.ClipIconView;
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -55,7 +56,8 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.InputConsumerController;
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* Temporary class to allow easier refactoring
@@ -72,9 +74,13 @@
@Override
- protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies,
- long duration, boolean isTargetTranslucent, boolean appCanEnterPip,
- RemoteAnimationTarget runningTaskTarget) {
+ protected HomeAnimationFactory createHomeAnimationFactory(
+ List<IBinder> launchCookies,
+ long duration,
+ boolean isTargetTranslucent,
+ boolean appCanEnterPip,
+ RemoteAnimationTarget runningTaskTarget,
+ @Nullable TaskView targetTaskView) {
if (mContainer == null) {
mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
isPresent -> mRecentsView.startHome());
@@ -86,8 +92,14 @@
};
}
- final View workspaceView = findWorkspaceView(launchCookies,
- mRecentsView.getRunningTaskView());
+ TaskView sourceTaskView = mRecentsView == null && targetTaskView == null
+ ? null
+ : targetTaskView == null
+ ? mRecentsView.getRunningTaskView()
+ : targetTaskView;
+ final View workspaceView = findWorkspaceView(
+ targetTaskView == null ? launchCookies : Collections.emptyList(),
+ sourceTaskView);
boolean canUseWorkspaceView = workspaceView != null
&& workspaceView.isAttachedToWindow()
&& workspaceView.getHeight() > 0
@@ -100,16 +112,24 @@
}
if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
- return new LauncherHomeAnimationFactory();
+ return new LauncherHomeAnimationFactory() {
+
+ @Nullable
+ @Override
+ public TaskView getTargetTaskView() {
+ return targetTaskView;
+ }
+ };
}
if (workspaceView instanceof LauncherAppWidgetHostView) {
return createWidgetHomeAnimationFactory((LauncherAppWidgetHostView) workspaceView,
isTargetTranslucent, runningTaskTarget);
}
- return createIconHomeAnimationFactory(workspaceView);
+ return createIconHomeAnimationFactory(workspaceView, targetTaskView);
}
- private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) {
+ private HomeAnimationFactory createIconHomeAnimationFactory(
+ View workspaceView, @Nullable TaskView targetTaskView) {
RectF iconLocation = new RectF();
FloatingIconView floatingIconView = getFloatingIconView(mContainer, workspaceView, null,
mContainer.getTaskbarUIController() == null
@@ -175,10 +195,35 @@
}
@Override
- public void update(RectF currentRect, float progress, float radius) {
- super.update(currentRect, progress, radius);
+ public void update(
+ RectF currentRect,
+ float progress,
+ float radius,
+ int overlayAlpha) {
floatingIconView.update(1f /* alpha */, currentRect, progress, windowAlphaThreshold,
- radius, false);
+ radius, false, overlayAlpha);
+ }
+
+ @Override
+ public boolean isAnimationReady() {
+ return floatingIconView.isLaidOut();
+ }
+
+ @Override
+ public void setTaskViewArtist(ClipIconView.TaskViewArtist taskViewArtist) {
+ super.setTaskViewArtist(taskViewArtist);
+ floatingIconView.setOverlayArtist(taskViewArtist);
+ }
+
+ @Override
+ public boolean isAnimatingIntoIcon() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public TaskView getTargetTaskView() {
+ return targetTaskView;
}
};
}
@@ -232,8 +277,8 @@
}
@Override
- public void update(RectF currentRect, float progress, float radius) {
- super.update(currentRect, progress, radius);
+ public void update(RectF currentRect, float progress, float radius, int overlayAlpha) {
+ super.update(currentRect, progress, radius, overlayAlpha);
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -254,13 +299,14 @@
* associated with the running task.
*/
@Nullable
- private View findWorkspaceView(ArrayList<IBinder> launchCookies, TaskView runningTaskView) {
+ private View findWorkspaceView(List<IBinder> launchCookies, TaskView sourceTaskView) {
if (mIsSwipingPipToHome) {
// Disable if swiping to PIP
return null;
}
- if (runningTaskView == null || runningTaskView.getTask() == null
- || runningTaskView.getTask().key.getComponent() == null) {
+ if (sourceTaskView == null
+ || sourceTaskView.getFirstTask() == null
+ || sourceTaskView.getFirstTask().key.getComponent() == null) {
// Disable if it's an invalid task
return null;
}
@@ -277,8 +323,8 @@
}
return mContainer.getFirstMatchForAppClose(launchCookieItemId,
- runningTaskView.getTask().key.getComponent().getPackageName(),
- UserHandle.of(runningTaskView.getTask().key.userId),
+ sourceTaskView.getFirstTask().key.getComponent().getPackageName(),
+ UserHandle.of(sourceTaskView.getFirstTask().key.userId),
false /* supportsAllAppsState */);
}
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 0a02e99..a71e314 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -109,6 +109,8 @@
* Sets a listener for changes in {@link #isHomeAndOverviewSame()}
*/
public void setOverviewChangeListener(Consumer<Boolean> overviewChangeListener) {
+ // TODO(b/337861962): This method should be able to support multiple listeners instead of
+ // one so that we can reuse the same instance of this class across multiple places
mOverviewChangeListener = overviewChangeListener;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 4b4f914..54466f3 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -33,6 +33,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
@@ -399,7 +400,8 @@
&& (mSystemUiStateFlags & SYSUI_STATE_MAGNIFICATION_OVERLAP) == 0
&& ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
|| (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0)
- && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0;
+ && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0
+ && (mSystemUiStateFlags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) == 0;
}
/**
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index bf50d70..3380291 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -39,6 +39,7 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.NavigationMode;
+import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -50,7 +51,7 @@
/**
* Helper class for transforming touch events
*/
-public class RotationTouchHelper implements DisplayInfoChangeListener {
+public class RotationTouchHelper implements DisplayInfoChangeListener, SafeCloseable {
public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
new MainThreadInitializedObject<>(RotationTouchHelper::new);
@@ -197,6 +198,11 @@
mOnDestroyActions.add(action);
}
+ @Override
+ public void close() {
+ destroy();
+ }
+
/**
* Cleans up all the registered listeners and receivers.
*/
diff --git a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
index f474796..29a57fc 100644
--- a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
@@ -24,22 +24,30 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
public class SimpleOrientationTouchTransformer implements
- DisplayController.DisplayInfoChangeListener {
+ DisplayController.DisplayInfoChangeListener, SafeCloseable {
public static final MainThreadInitializedObject<SimpleOrientationTouchTransformer> INSTANCE =
new MainThreadInitializedObject<>(SimpleOrientationTouchTransformer::new);
+ private final Context mContext;
private OrientationRectF mOrientationRectF;
public SimpleOrientationTouchTransformer(Context context) {
+ mContext = context;
DisplayController.INSTANCE.get(context).addChangeListener(this);
onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
CHANGE_ALL);
}
@Override
+ public void close() {
+ DisplayController.INSTANCE.get(mContext).removeChangeListener(this);
+ }
+
+ @Override
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN)) == 0) {
return;
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 5ff9787..fb54241 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.ACCELERATE_1_5;
import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.PagedView.INVALID_PAGE;
import android.animation.Animator;
import android.content.Context;
@@ -27,6 +28,7 @@
import android.view.RemoteAnimationTarget;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
@@ -36,6 +38,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.views.ClipIconView;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.AnimatorControllerWithResistance;
@@ -46,6 +49,8 @@
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
import java.util.Arrays;
import java.util.function.Consumer;
@@ -201,7 +206,7 @@
public void setAnimation(RectFSpringAnim anim) { }
- public void update(RectF currentRect, float progress, float radius) { }
+ public void update(RectF currentRect, float progress, float radius, int overlayAlpha) { }
public void onCancel() { }
@@ -222,6 +227,33 @@
}
return Utilities.mapToRange(progress, start, end, 1, 0, ACCELERATE_1_5);
}
+
+ /**
+ * Sets a {@link com.android.launcher3.views.ClipIconView.TaskViewArtist} that should be
+ * used draw a {@link TaskView} during this home animation.
+ */
+ public void setTaskViewArtist(ClipIconView.TaskViewArtist taskViewArtist) { }
+
+ public boolean isAnimationReady() {
+ return true;
+ }
+
+ public boolean isAnimatingIntoIcon() {
+ return false;
+ }
+
+ @Nullable
+ public TaskView getTargetTaskView() {
+ return null;
+ }
+
+ public boolean isRtl() {
+ return Utilities.isRtl(mContext.getResources());
+ }
+
+ public boolean isPortrait() {
+ return !mDp.isLandscape && !mDp.isSeascape();
+ }
}
/**
@@ -276,9 +308,13 @@
for (int i = 0, mRemoteTargetHandlesLength = mRemoteTargetHandles.length;
i < mRemoteTargetHandlesLength; i++) {
RemoteTargetHandle remoteHandle = mRemoteTargetHandles[i];
- out[i] = getWindowAnimationToHomeInternal(homeAnimationFactory,
- targetRect, remoteHandle.getTransformParams(),
- remoteHandle.getTaskViewSimulator(), startRects[i], homeToWindowPositionMap[i]);
+ out[i] = getWindowAnimationToHomeInternal(
+ homeAnimationFactory,
+ targetRect,
+ remoteHandle.getTransformParams(),
+ remoteHandle.getTaskViewSimulator(),
+ startRects[i],
+ homeToWindowPositionMap[i]);
}
return out;
}
@@ -288,21 +324,39 @@
}
private RectFSpringAnim getWindowAnimationToHomeInternal(
- HomeAnimationFactory homeAnimationFactory, RectF targetRect,
- TransformParams transformParams, TaskViewSimulator taskViewSimulator,
- RectF startRect, Matrix homeToWindowPositionMap) {
+ HomeAnimationFactory homeAnimationFactory,
+ RectF targetRect,
+ TransformParams transformParams,
+ TaskViewSimulator taskViewSimulator,
+ RectF startRect,
+ Matrix homeToWindowPositionMap) {
RectF cropRectF = new RectF(taskViewSimulator.getCurrentCropRect());
// Move the startRect to Launcher space as floatingIconView runs in Launcher
Matrix windowToHomePositionMap = new Matrix();
- // If the start rect ends up overshooting too much to the left/right offscreen, bring it
- // back to fullscreen. This can happen when the recentsScroll value isn't aligned with
- // the pageScroll value for a given taskView, see b/228829958#comment12
- mRemoteTargetHandles[0].getTaskViewSimulator().getOrientationState().getOrientationHandler()
- .fixBoundsForHomeAnimStartRect(startRect, mDp);
+ TaskView targetTaskView = homeAnimationFactory.getTargetTaskView();
+ if (targetTaskView == null) {
+ // If the start rect ends up overshooting too much to the left/right offscreen, bring it
+ // back to fullscreen. This can happen when the recentsScroll value isn't aligned with
+ // the pageScroll value for a given taskView, see b/228829958#comment12
+ mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getOrientationState()
+ .getOrientationHandler()
+ .fixBoundsForHomeAnimStartRect(startRect, mDp);
+ }
homeToWindowPositionMap.invert(windowToHomePositionMap);
windowToHomePositionMap.mapRect(startRect);
+ RectF invariantStartRect = new RectF(startRect);
+
+ if (targetTaskView != null) {
+ Rect thumbnailBounds = new Rect();
+ targetTaskView.getThumbnailBounds(thumbnailBounds, /* relativeToDragLayer= */ true);
+
+ invariantStartRect = new RectF(thumbnailBounds);
+ invariantStartRect.offsetTo(startRect.left, thumbnailBounds.top);
+ startRect = new RectF(thumbnailBounds);
+ }
boolean useTaskbarHotseatParams = mDp.isTaskbarPresent
&& homeAnimationFactory.isInHotseat();
@@ -312,8 +366,12 @@
homeAnimationFactory.setAnimation(anim);
SpringAnimationRunner runner = new SpringAnimationRunner(
- homeAnimationFactory, cropRectF, homeToWindowPositionMap,
- transformParams, taskViewSimulator);
+ homeAnimationFactory,
+ cropRectF,
+ homeToWindowPositionMap,
+ transformParams,
+ taskViewSimulator,
+ invariantStartRect);
anim.addAnimatorListener(runner);
anim.addOnUpdateListener(runner);
return anim;
@@ -336,9 +394,30 @@
final float mStartRadius;
final float mEndRadius;
- SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
- Matrix homeToWindowPositionMap, TransformParams transformParams,
- TaskViewSimulator taskViewSimulator) {
+ final RectF mRunningTaskViewStartRectF;
+ @Nullable
+ final TaskView mTargetTaskView;
+ final float mRunningTaskViewScrollOffset;
+ final float mTaskViewWidth;
+ final float mTaskViewHeight;
+ final boolean mIsPortrait;
+ final Rect mThumbnailStartBounds = new Rect();
+
+ // Store the mTargetTaskView view properties onAnimationStart so that we can reset them
+ // when cleaning up.
+ float mTaskViewAlpha;
+ float mTaskViewTranslationX;
+ float mTaskViewTranslationY;
+ float mTaskViewScaleX;
+ float mTaskViewScaleY;
+
+ SpringAnimationRunner(
+ HomeAnimationFactory factory,
+ RectF cropRectF,
+ Matrix homeToWindowPositionMap,
+ TransformParams transformParams,
+ TaskViewSimulator taskViewSimulator,
+ RectF invariantStartRect) {
mAnimationFactory = factory;
mHomeAnim = factory.createActivityAnimationToHome();
mCropRectF = cropRectF;
@@ -351,22 +430,62 @@
// rounding at the end of the animation.
mStartRadius = taskViewSimulator.getCurrentCornerRadius();
mEndRadius = factory.getEndRadius(cropRectF);
+
+ mRunningTaskViewStartRectF = invariantStartRect;
+ mTargetTaskView = factory.getTargetTaskView();
+ mTaskViewWidth = mTargetTaskView == null ? 0 : mTargetTaskView.getWidth();
+ mTaskViewHeight = mTargetTaskView == null ? 0 : mTargetTaskView.getHeight();
+ mIsPortrait = factory.isPortrait();
+ // Use the running task's start position to determine how much it needs to be offset
+ // to end up offscreen.
+ mRunningTaskViewScrollOffset = factory.isRtl()
+ ? (Math.min(0, -invariantStartRect.right))
+ : (Math.max(0, mDp.widthPx - invariantStartRect.left));
}
@Override
public void onUpdate(RectF currentRect, float progress) {
- mHomeAnim.setPlayFraction(progress);
- mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
-
- mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
float alpha = mAnimationFactory.getWindowAlpha(progress);
- mLocalTransformParams
- .setTargetAlpha(alpha)
- .setCornerRadius(cornerRadius);
- mLocalTransformParams.applySurfaceParams(mLocalTransformParams
- .createSurfaceParams(this));
- mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
+
+ mHomeAnim.setPlayFraction(progress);
+ if (mTargetTaskView == null) {
+ mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
+ mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
+ mLocalTransformParams
+ .setTargetAlpha(alpha)
+ .setCornerRadius(cornerRadius);
+ } else {
+ mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, mRunningTaskViewStartRectF);
+ mWindowCurrentRect.offset(mRunningTaskViewScrollOffset * progress, 0f);
+ mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
+ mLocalTransformParams.setCornerRadius(mStartRadius);
+ }
+
+ mLocalTransformParams.applySurfaceParams(
+ mLocalTransformParams.createSurfaceParams(this));
+ mAnimationFactory.update(
+ currentRect, progress, mMatrix.mapRadius(cornerRadius), (int) (alpha * 255));
+
+ if (mTargetTaskView == null) {
+ return;
+ }
+ if (mAnimationFactory.isAnimatingIntoIcon() && mAnimationFactory.isAnimationReady()) {
+ mTargetTaskView.setAlpha(0f);
+ return;
+ }
+ mTargetTaskView.setAlpha(mAnimationFactory.isAnimatingIntoIcon() ? 1f : alpha);
+ float width = mThumbnailStartBounds.width();
+ float height = mThumbnailStartBounds.height();
+ float scale = Math.min(currentRect.width(), currentRect.height())
+ / Math.min(width, height);
+
+ mTargetTaskView.setScaleX(scale);
+ mTargetTaskView.setScaleY(scale);
+ mTargetTaskView.setTranslationX(
+ currentRect.centerX() - mThumbnailStartBounds.centerX());
+ mTargetTaskView.setTranslationY(
+ currentRect.centerY() - mThumbnailStartBounds.centerY());
}
@Override
@@ -379,16 +498,71 @@
@Override
public void onCancel() {
+ cleanUp();
mAnimationFactory.onCancel();
}
@Override
public void onAnimationStart(Animator animation) {
+ setUp();
mHomeAnim.dispatchOnStart();
+ if (mTargetTaskView == null) {
+ return;
+ }
+ Rect thumbnailBounds = new Rect();
+ // Use bounds relative to mTargetTaskView since it will be scaled afterwards
+ mTargetTaskView.getThumbnailBounds(thumbnailBounds);
+ mAnimationFactory.setTaskViewArtist(new ClipIconView.TaskViewArtist(
+ mTargetTaskView::draw,
+ 0f,
+ -thumbnailBounds.top,
+ Math.min(mTaskViewHeight, mTaskViewWidth),
+ mIsPortrait));
+ }
+
+ private void setUp() {
+ if (mTargetTaskView == null) {
+ return;
+ }
+ RecentsView recentsView = mTargetTaskView.getRecentsView();
+ if (recentsView != null) {
+ recentsView.setOffsetMidpointIndexOverride(
+ recentsView.indexOfChild(mTargetTaskView));
+ }
+ mTargetTaskView.getThumbnailBounds(
+ mThumbnailStartBounds, /* relativeToDragLayer= */ true);
+ mTaskViewAlpha = mTargetTaskView.getAlpha();
+ if (mAnimationFactory.isAnimatingIntoIcon()) {
+ return;
+ }
+ mTaskViewTranslationX = mTargetTaskView.getTranslationX();
+ mTaskViewTranslationY = mTargetTaskView.getTranslationY();
+ mTaskViewScaleX = mTargetTaskView.getScaleX();
+ mTaskViewScaleY = mTargetTaskView.getScaleY();
+ }
+
+ private void cleanUp() {
+ if (mTargetTaskView == null) {
+ return;
+ }
+ RecentsView recentsView = mTargetTaskView.getRecentsView();
+ if (recentsView != null) {
+ recentsView.setOffsetMidpointIndexOverride(INVALID_PAGE);
+ }
+ mTargetTaskView.setAlpha(mTaskViewAlpha);
+ if (!mAnimationFactory.isAnimatingIntoIcon()) {
+ mTargetTaskView.setTranslationX(mTaskViewTranslationX);
+ mTargetTaskView.setTranslationY(mTaskViewTranslationY);
+ mTargetTaskView.setScaleX(mTaskViewScaleX);
+ mTargetTaskView.setScaleY(mTaskViewScaleY);
+ return;
+ }
+ mAnimationFactory.setTaskViewArtist(null);
}
@Override
public void onAnimationSuccess(Animator animator) {
+ cleanUp();
mHomeAnim.getAnimationPlayer().end();
}
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 30bb863..e745112 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -23,6 +23,8 @@
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -32,7 +34,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.graphics.Point;
import android.graphics.Rect;
@@ -65,6 +66,7 @@
import com.android.internal.view.AppearanceRegion;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AssistUtils;
import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
@@ -108,8 +110,8 @@
/**
* Holds the reference to SystemUI.
*/
-public class SystemUiProxy implements ISystemUiProxy, NavHandle {
- private static final String TAG = SystemUiProxy.class.getSimpleName();
+public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
+ private static final String TAG = "SystemUiProxy";
public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
new MainThreadInitializedObject<>(SystemUiProxy::new);
@@ -199,6 +201,9 @@
}
@Override
+ public void close() { }
+
+ @Override
public void onBackPressed() {
if (mSystemUiProxy != null) {
try {
@@ -454,10 +459,11 @@
}
@Override
- public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+ public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier,
+ boolean haptic) {
if (mSystemUiProxy != null) {
try {
- mSystemUiProxy.setOverrideHomeButtonLongPress(duration, slopMultiplier);
+ mSystemUiProxy.setOverrideHomeButtonLongPress(duration, slopMultiplier, haptic);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setOverrideHomeButtonLongPress", e);
}
@@ -569,6 +575,17 @@
}
}
+ @Override
+ public void toggleQuickSettingsPanel() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.toggleQuickSettingsPanel();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call toggleQuickSettingsPanel", e);
+ }
+ }
+ }
+
//
// Pip
//
@@ -794,15 +811,29 @@
/**
* Tells SysUI when the bubble is being dragged.
* Should be called only when the bubble bar is expanded.
- * @param bubbleKey the key of the bubble to collapse/expand
- * @param isBeingDragged whether the bubble is being dragged
+ * @param bubbleKey key of the bubble being dragged
*/
- public void onBubbleDrag(@Nullable String bubbleKey, boolean isBeingDragged) {
+ public void startBubbleDrag(@Nullable String bubbleKey) {
if (mBubbles == null) return;
try {
- mBubbles.onBubbleDrag(bubbleKey, isBeingDragged);
+ mBubbles.startBubbleDrag(bubbleKey);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call onBubbleDrag");
+ Log.w(TAG, "Failed call startBubbleDrag");
+ }
+ }
+
+ /**
+ * Tells SysUI when the bubble stops being dragged.
+ * Should be called only when the bubble bar is expanded.
+ * @param bubbleKey key of the bubble being dragged
+ * @param location location of the bubble bar
+ */
+ public void stopBubbleDrag(@Nullable String bubbleKey, BubbleBarLocation location) {
+ if (mBubbles == null) return;
+ try {
+ mBubbles.stopBubbleDrag(bubbleKey, location);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call stopBubbleDrag");
}
}
@@ -1366,8 +1397,7 @@
* Gets the set of running tasks.
*/
public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
- if (mRecentTasks != null
- && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
+ if (mRecentTasks != null && shouldEnableRunningTasksForDesktopMode()) {
try {
return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
} catch (RemoteException e) {
@@ -1377,6 +1407,11 @@
return new ArrayList<>();
}
+ private boolean shouldEnableRunningTasksForDesktopMode() {
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
+ }
+
private boolean handleMessageAsync(Message msg) {
switch (msg.what) {
case MSG_SET_SHELF_HEIGHT:
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index dec8a12..2348f28 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -54,11 +54,11 @@
import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
- public static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
+ 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);
+ private final Context mCtx;
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
@@ -66,7 +66,6 @@
private GestureState mLastGestureState;
private RemoteAnimationTarget[] mLastAppearedTaskTargets;
private Runnable mLiveTileCleanUpHandler;
- private Context mCtx;
private boolean mRecentsAnimationStartPending = false;
private boolean mShouldIgnoreMotionEvents = false;
@@ -329,7 +328,7 @@
options.setTransientLaunch();
}
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
- mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.getNoCreate()
+ mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.get(mCtx)
.startRecentsActivity(intent, options, mCallbacks);
if (enableHandleDelayedGestureCallbacks()) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 18b8e3e..1a46fb6 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -16,8 +16,6 @@
package com.android.quickstep;
-import static android.view.Surface.ROTATION_0;
-
import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
@@ -33,7 +31,6 @@
import androidx.annotation.RequiresApi;
import com.android.launcher3.BaseActivity;
-import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -42,13 +39,14 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.Snackbar;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -61,13 +59,15 @@
public class TaskOverlayFactory implements ResourceBasedOverride {
public static List<SystemShortcut> getEnabledShortcuts(TaskView taskView,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
final ArrayList<SystemShortcut> shortcuts = new ArrayList<>();
final RecentsViewContainer container =
RecentsViewContainer.containerFromContext(taskView.getContext());
- boolean hasMultipleTasks = taskView.getTaskIds()[1] != -1;
for (TaskShortcutFactory menuOption : MENU_OPTIONS) {
- if (hasMultipleTasks && !menuOption.showForSplitscreen()) {
+ if (taskView instanceof GroupedTaskView && !menuOption.showForGroupedTask()) {
+ continue;
+ }
+ if (taskView instanceof DesktopTaskView && !menuOption.showForDesktopTask()) {
continue;
}
@@ -77,37 +77,10 @@
}
shortcuts.addAll(menuShortcuts);
}
- RecentsOrientedState orientedState = taskView.getRecentsView().getPagedViewOrientedState();
- boolean canLauncherRotate = orientedState.isRecentsActivityRotationAllowed();
- boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
- boolean isTablet = container.getDeviceProfile().isTablet;
-
- boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
- // Add overview actions to the menu when:
- // - single task is showing
- // - in in-place rotate landscape mode, or in grid-only overview.
- if (!hasMultipleTasks && ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview)) {
- // Add screenshot action to task menu.
- List<SystemShortcut> screenshotShortcuts = TaskShortcutFactory.SCREENSHOT
- .getShortcuts(container, taskContainer);
- if (screenshotShortcuts != null) {
- shortcuts.addAll(screenshotShortcuts);
- }
-
- // Add modal action only if display orientation is the same as the device orientation,
- // or in grid-only overview.
- if (orientedState.getDisplayRotation() == ROTATION_0 || isGridOnlyOverview) {
- List<SystemShortcut> modalShortcuts = TaskShortcutFactory.MODAL
- .getShortcuts(container, taskContainer);
- if (modalShortcuts != null) {
- shortcuts.addAll(modalShortcuts);
- }
- }
- }
return shortcuts;
}
- public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
+ public TaskOverlay createOverlay(TaskThumbnailViewDeprecated thumbnailView) {
return new TaskOverlay(thumbnailView);
}
@@ -140,7 +113,9 @@
TaskShortcutFactory.FREE_FORM,
DesktopSystemShortcut.Companion.createFactory(),
TaskShortcutFactory.WELLBEING,
- TaskShortcutFactory.SAVE_APP_PAIR
+ TaskShortcutFactory.SAVE_APP_PAIR,
+ TaskShortcutFactory.SCREENSHOT,
+ TaskShortcutFactory.MODAL
};
/**
@@ -149,14 +124,14 @@
public static class TaskOverlay<T extends OverviewActionsView> {
protected final Context mApplicationContext;
- protected final TaskThumbnailView mThumbnailView;
+ protected final TaskThumbnailViewDeprecated mThumbnailView;
private T mActionsView;
protected ImageActionsApi mImageApi;
- protected TaskOverlay(TaskThumbnailView taskThumbnailView) {
- mApplicationContext = taskThumbnailView.getContext().getApplicationContext();
- mThumbnailView = taskThumbnailView;
+ protected TaskOverlay(TaskThumbnailViewDeprecated taskThumbnailViewDeprecated) {
+ mApplicationContext = taskThumbnailViewDeprecated.getContext().getApplicationContext();
+ mThumbnailView = taskThumbnailViewDeprecated;
mImageApi = new ImageActionsApi(
mApplicationContext, mThumbnailView::getThumbnail);
}
@@ -169,7 +144,7 @@
return mActionsView;
}
- public TaskThumbnailView getThumbnailView() {
+ public TaskThumbnailViewDeprecated getThumbnailView() {
return mThumbnailView;
}
@@ -317,7 +292,7 @@
@Override
public void onClick(View view) {
- saveScreenshot(mThumbnailView.getTaskView().getTask());
+ saveScreenshot(mThumbnailView.getTaskView().getFirstTask());
dismissTaskMenuView();
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 9d10ac1..a53d91f 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
@@ -39,6 +40,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
@@ -50,19 +52,19 @@
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@@ -75,11 +77,21 @@
public interface TaskShortcutFactory {
@Nullable
default List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
return null;
}
- default boolean showForSplitscreen() {
+ /**
+ * Returns {@code true} if it should be shown for grouped task; {@code false} otherwise.
+ */
+ default boolean showForGroupedTask() {
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if it should be shown for desktop task; {@code false} otherwise.
+ */
+ default boolean showForDesktopTask() {
return false;
}
@@ -95,7 +107,7 @@
TaskShortcutFactory APP_INFO = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
TaskView taskView = taskContainer.getTaskView();
AppInfo.SplitAccessibilityInfo accessibilityInfo =
new AppInfo.SplitAccessibilityInfo(taskView.containsMultipleTasks(),
@@ -107,7 +119,7 @@
}
@Override
- public boolean showForSplitscreen() {
+ public boolean showForGroupedTask() {
return true;
}
};
@@ -158,12 +170,12 @@
private Handler mHandler;
private final RecentsView mRecentsView;
- private final TaskThumbnailView mThumbnailView;
+ private final TaskThumbnailViewDeprecated mThumbnailView;
private final TaskView mTaskView;
private final LauncherEvent mLauncherEvent;
public FreeformSystemShortcut(int iconRes, int textRes, RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer, LauncherEvent launcherEvent) {
+ TaskContainer taskContainer, LauncherEvent launcherEvent) {
super(iconRes, textRes, container, taskContainer.getItemInfo(),
taskContainer.getTaskView());
mLauncherEvent = launcherEvent;
@@ -186,7 +198,7 @@
}
private void startActivity() {
- final Task.TaskKey taskKey = mTaskView.getTask().key;
+ final Task.TaskKey taskKey = mTaskView.getFirstTask().key;
final int taskId = taskKey.id;
final ActivityOptions options = makeLaunchOptions(mTarget);
if (options != null) {
@@ -279,7 +291,7 @@
TaskShortcutFactory SPLIT_SELECT = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
DeviceProfile deviceProfile = container.getDeviceProfile();
final Task task = taskContainer.getTask();
final int intentFlags = task.key.baseIntent.getFlags();
@@ -314,7 +326,7 @@
@Nullable
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
DeviceProfile deviceProfile = container.getDeviceProfile();
final TaskView taskView = taskContainer.getTaskView();
final RecentsView recentsView = taskView.getRecentsView();
@@ -323,24 +335,15 @@
recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
boolean shouldShowActionsButtonInstead =
isLargeTileFocusedTask && isInExpectedScrollPosition;
- boolean hasUnpinnableApp = Arrays.stream(taskView.getTaskIdAttributeContainers())
- .anyMatch(att -> att != null && att.getItemInfo() != null
- && ((att.getItemInfo().runtimeStatusFlags
- & ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
// No "save app pair" menu item if:
- // - app pairs feature is not enabled
// - we are in 3p launcher
- // - the task in question is a single task
- // - at least one app in app pair is unpinnable
// - the Overview Actions Button should be visible
- // - the task is not a GroupedTaskView
- if (!FeatureFlags.enableAppPairs()
- || !recentsView.supportsAppPairs()
- || !taskView.containsMultipleTasks()
- || hasUnpinnableApp
+ // - the task view is not a valid save-able split pair
+ if (!recentsView.supportsAppPairs()
|| shouldShowActionsButtonInstead
- || !(taskView instanceof GroupedTaskView)) {
+ || !recentsView.getSplitSelectController().getAppPairsController()
+ .canSaveAppPair(taskView)) {
return null;
}
@@ -354,7 +357,7 @@
}
@Override
- public boolean showForSplitscreen() {
+ public boolean showForGroupedTask() {
return true;
}
};
@@ -362,7 +365,7 @@
TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
final Task task = taskContainer.getTask();
if (!task.isDockable) {
return null;
@@ -388,7 +391,7 @@
TaskShortcutFactory PIN = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
if (!SystemUiProxy.INSTANCE.get(container.asContext()).isActive()) {
return null;
}
@@ -410,7 +413,7 @@
private final TaskView mTaskView;
public PinSystemShortcut(RecentsViewContainer target,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
super(R.drawable.ic_pin, R.string.recent_task_option_pin, target,
taskContainer.getItemInfo(), taskContainer.getTaskView());
mTaskView = taskContainer.getTaskView();
@@ -420,7 +423,7 @@
public void onClick(View view) {
if (mTaskView.launchTaskAnimated() != null) {
SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning(
- mTaskView.getTask().key.id);
+ mTaskView.getFirstTask().key.id);
}
dismissTaskMenuView();
mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getItemInfo())
@@ -431,7 +434,7 @@
TaskShortcutFactory INSTALL = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
Task t = taskContainer.getTask();
return InstantAppResolver.newInstance(container.asContext()).isInstantApp(
t.getTopComponent().getPackageName(), t.getKey().userId)
@@ -444,7 +447,7 @@
TaskShortcutFactory WELLBEING = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
SystemShortcut<ActivityContext> wellbeingShortcut =
WellbeingModel.SHORTCUT_FACTORY.getShortcut(container,
taskContainer.getItemInfo(), taskContainer.getTaskView());
@@ -455,19 +458,54 @@
TaskShortcutFactory SCREENSHOT = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
+ boolean isTablet = container.getDeviceProfile().isTablet;
+ boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
+ // Extra conditions if it's not grid-only overview
+ if (!isGridOnlyOverview) {
+ RecentsOrientedState orientedState =
+ taskContainer.getTaskView().getRecentsView().getPagedViewOrientedState();
+ boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
+ && orientedState.getTouchRotation() != ROTATION_0;
+ if (!isFakeLandscape) {
+ return null;
+ }
+ }
+
SystemShortcut screenshotShortcut =
taskContainer.getThumbnailView().getTaskOverlay()
.getScreenshotShortcut(container, taskContainer.getItemInfo(),
taskContainer.getTaskView());
return createSingletonShortcutList(screenshotShortcut);
}
+
+ @Override
+ public boolean showForDesktopTask() {
+ return true;
+ }
};
TaskShortcutFactory MODAL = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
+ boolean isTablet = container.getDeviceProfile().isTablet;
+ boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
+ // Extra conditions if it's not grid-only overview
+ if (!isGridOnlyOverview) {
+ RecentsOrientedState orientedState =
+ taskContainer.getTaskView().getRecentsView().getPagedViewOrientedState();
+ boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
+ && orientedState.getTouchRotation() != ROTATION_0;
+ if (!isFakeLandscape) {
+ return null;
+ }
+ // Disallow "Select" when swiping up from landscape due to rotated thumbnail.
+ if (orientedState.getDisplayRotation() != ROTATION_0) {
+ return null;
+ }
+ }
+
SystemShortcut modalStateSystemShortcut =
taskContainer.getThumbnailView().getTaskOverlay()
.getModalStateSystemShortcut(
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index b7cbb47..f6eef62 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -148,7 +148,7 @@
* @param callback The callback to receive the task after its data has been populated.
* @return A cancelable handle to the request
*/
- public CancellableTask updateThumbnailInBackground(
+ public CancellableTask<ThumbnailData> updateThumbnailInBackground(
Task task, Consumer<ThumbnailData> callback) {
Preconditions.assertUIThread();
@@ -184,8 +184,8 @@
return newSize > oldSize;
}
- private CancellableTask updateThumbnailInBackground(TaskKey key, boolean lowResolution,
- Consumer<ThumbnailData> callback) {
+ private CancellableTask<ThumbnailData> updateThumbnailInBackground(TaskKey key,
+ boolean lowResolution, Consumer<ThumbnailData> callback) {
Preconditions.assertUIThread();
ThumbnailData cachedThumbnail = mCache.getAndInvalidateIfModified(key);
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 80a449b..63e536a 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -70,7 +70,7 @@
return "";
}
UserHandle user = UserHandle.of(userId);
- ApplicationInfo applicationInfo = new PackageManagerHelper(context)
+ ApplicationInfo applicationInfo = PackageManagerHelper.INSTANCE.get(context)
.getApplicationInfo(packageName, user, 0);
if (applicationInfo == null) {
Log.e(TAG, "Failed to get title for userId=" + userId + ", packageName=" + packageName);
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 450e960..d2560e6 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -80,7 +80,7 @@
import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
import com.android.systemui.animation.RemoteAnimationTargetCompat;
import com.android.systemui.shared.recents.model.Task;
@@ -121,7 +121,7 @@
for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
TaskView taskView = recentsView.getTaskViewAt(i);
if (recentsView.isTaskViewVisible(taskView)) {
- Task.TaskKey key = taskView.getTask().key;
+ Task.TaskKey key = taskView.getFirstTask().key;
if (componentName.equals(key.getComponent()) && userId == key.userId) {
return taskView;
}
@@ -334,7 +334,7 @@
// During animation we apply transformation on the thumbnailView (and not the rootView)
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
// Mt K(0)` K(t) Mt`
- TaskThumbnailView[] thumbnails = v.getThumbnails();
+ TaskThumbnailViewDeprecated[] thumbnails = v.getThumbnailViews();
// In case simulator copies and thumbnail size do no match, ensure we get the lesser.
// This ensures we do not create arrays with empty elements or attempt to references
@@ -344,7 +344,7 @@
Matrix[] mt = new Matrix[matrixSize];
Matrix[] mti = new Matrix[matrixSize];
for (int i = 0; i < matrixSize; i++) {
- TaskThumbnailView ttv = thumbnails[i];
+ TaskThumbnailViewDeprecated ttv = thumbnails[i];
RectF localBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
@@ -391,7 +391,7 @@
out.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- for (TaskThumbnailView ttv : thumbnails) {
+ for (TaskThumbnailViewDeprecated ttv : thumbnails) {
ttv.setAnimationMatrix(null);
}
}
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index a2a6dde..3a6b804 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -34,6 +34,7 @@
import androidx.annotation.UiThread;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitStageInfo;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
@@ -57,7 +58,8 @@
* This class tracked the top-most task and some 'approximate' task history to allow faster
* system state estimation during touch interaction
*/
-public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskStackChangeListener {
+public class TopTaskTracker extends ISplitScreenListener.Stub
+ implements TaskStackChangeListener, SafeCloseable {
public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
new MainThreadInitializedObject<>(TopTaskTracker::new);
@@ -67,12 +69,13 @@
// Ordered list with first item being the most recent task.
private final LinkedList<RunningTaskInfo> mOrderedTaskList = new LinkedList<>();
-
+ private final Context mContext;
private final SplitStageInfo mMainStagePosition = new SplitStageInfo();
private final SplitStageInfo mSideStagePosition = new SplitStageInfo();
private int mPinnedTaskId = INVALID_TASK_ID;
private TopTaskTracker(Context context) {
+ mContext = context;
mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
@@ -81,6 +84,12 @@
}
@Override
+ public void close() {
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(this);
+ SystemUiProxy.INSTANCE.get(mContext).unregisterSplitScreenListener(this);
+ }
+
+ @Override
public void onTaskRemoved(int taskId) {
mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index a842b51..f94a29c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -94,6 +94,7 @@
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.testing.TestLogging;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -470,6 +471,18 @@
private final ScreenOnTracker.ScreenOnListener mScreenOnListener = this::onScreenOnChanged;
+ private final TaskbarNavButtonCallbacks mNavCallbacks = new TaskbarNavButtonCallbacks() {
+ @Override
+ public void onNavigateHome() {
+ mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
+ }
+
+ @Override
+ public void onToggleOverview() {
+ mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
+ }
+ };
+
private ActivityManagerWrapper mAM;
private OverviewCommandHelper mOverviewCommandHelper;
private OverviewComponentObserver mOverviewComponentObserver;
@@ -500,7 +513,7 @@
mDeviceState = new RecentsAnimationDeviceState(this, true);
mAllAppsActionManager = new AllAppsActionManager(
this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
- mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager);
+ mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks);
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
@@ -1005,7 +1018,7 @@
.append("TaskbarActivityContext != null, ")
.append("using TaskbarUnstashInputConsumer");
base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
- mOverviewCommandHelper);
+ mOverviewCommandHelper, mGestureState);
}
}
if (enableBubblesLongPressNavHandle()) {
@@ -1033,7 +1046,7 @@
}
reasonString.append("using NavHandleLongPressInputConsumer");
base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
- mDeviceState, navHandle);
+ mDeviceState, navHandle, mGestureState);
}
if (!enableBubblesLongPressNavHandle()) {
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 2e76356..644e4f9 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -42,16 +42,14 @@
import androidx.annotation.NonNull;
+import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.util.MultiPropertyFactory;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.ClearAllButton;
-import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.RecentsViewContainer;
/**
* State controller for fallback recents activity
@@ -99,7 +97,7 @@
clearAllButtonAlpha, LINEAR);
float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0;
setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
- MultiPropertyFactory.MULTI_PROPERTY_VALUE, overviewButtonAlpha, LINEAR);
+ AnimatedFloat.VALUE, overviewButtonAlpha, LINEAR);
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0],
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index d881a1f..b79586b 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -53,6 +53,7 @@
import com.android.systemui.shared.recents.model.Task;
import java.util.ArrayList;
+import java.util.Arrays;
public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
implements StateListener<RecentsState> {
@@ -144,8 +145,9 @@
@Override
public void setCurrentTask(int runningTaskViewId) {
super.setCurrentTask(runningTaskViewId);
- int runningTaskId = getTaskIdsForRunningTaskView()[0];
- if (mHomeTask != null && mHomeTask.key.id != runningTaskId) {
+ int[] runningTaskIds = getTaskIdsForRunningTaskView();
+ if (mHomeTask != null
+ && Arrays.stream(runningTaskIds).noneMatch(taskId -> taskId == mHomeTask.key.id)) {
mHomeTask = null;
setRunningTaskHidden(false);
}
@@ -182,13 +184,14 @@
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
// TODO(b/195607777) Confirm home task info is front-most task and not mixed in with others
- int runningTaskId = getTaskIdsForRunningTaskView()[0];
- if (mHomeTask != null && mHomeTask.key.id == runningTaskId
+ int[] runningTaskIds = getTaskIdsForRunningTaskView();
+ if (mHomeTask != null
+ && Arrays.stream(runningTaskIds).allMatch(taskId -> taskId == mHomeTask.key.id)
&& !taskGroups.isEmpty()) {
// Check if the task list has running task
boolean found = false;
for (GroupTask group : taskGroups) {
- if (group.containsTask(runningTaskId)) {
+ if (Arrays.stream(runningTaskIds).allMatch(group::containsTask)) {
found = true;
break;
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 075e539..848a43a 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -31,6 +31,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.DeviceConfigWrapper;
+import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.NavHandle;
import com.android.quickstep.RecentsAnimationDeviceState;
@@ -61,13 +62,14 @@
private final NavHandle mNavHandle;
private final StatsLogManager mStatsLogManager;
private final TopTaskTracker mTopTaskTracker;
+ private final GestureState mGestureState;
private MotionEvent mCurrentDownEvent;
private boolean mDeepPressLogged; // Whether deep press has been logged for the current touch.
public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState,
- NavHandle navHandle) {
+ NavHandle navHandle, GestureState gestureState) {
super(delegate, inputMonitor);
mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
mDeepPressEnabled = DeviceConfigWrapper.get().getEnableLpnhDeepPress();
@@ -82,6 +84,8 @@
mTouchSlopSquaredOriginal = deviceState.getSquaredTouchSlop();
mTouchSlopSquared = mTouchSlopSquaredOriginal;
mOuterTouchSlopSquared = mTouchSlopSquared * (twoStageMultiplier * twoStageMultiplier);
+ mGestureState = gestureState;
+ mGestureState.setIsInExtendedSlopRegion(false);
if (DEBUG_NAV_HANDLE) {
Log.d(TAG, "mLongPressTimeout=" + mLongPressTimeout);
Log.d(TAG, "mOuterLongPressTimeout=" + mOuterLongPressTimeout);
@@ -126,6 +130,7 @@
}
mCurrentDownEvent = MotionEvent.obtain(ev);
mTouchSlopSquared = mTouchSlopSquaredOriginal;
+ mGestureState.setIsInExtendedSlopRegion(false);
mDeepPressLogged = false;
if (isInNavBarHorizontalArea(ev.getRawX())) {
mNavHandleLongPressHandler.onTouchStarted(mNavHandle);
@@ -154,6 +159,7 @@
- (int) (ev.getEventTime() - ev.getDownTime());
MAIN_EXECUTOR.getHandler().postDelayed(mTriggerLongPress, delay);
mTouchSlopSquared = mOuterTouchSlopSquared;
+ mGestureState.setIsInExtendedSlopRegion(true);
if (DEBUG_NAV_HANDLE) {
Log.d(TAG, "Touch in middle region!");
}
@@ -219,6 +225,7 @@
if (DEBUG_NAV_HANDLE) {
Log.d(TAG, "cancelLongPress");
}
+ mGestureState.setIsInExtendedSlopRegion(false);
MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
mNavHandleLongPressHandler.onTouchFinished(mNavHandle, reason);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 9f39476..0d450c6 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -284,8 +284,9 @@
float horizontalDist = Math.abs(displacementX);
float upDist = -displacement;
- boolean passedSlop = mGestureState.isTrackpadGesture() || squaredHypot(
- displacementX, displacementY) >= mSquaredTouchSlop;
+ boolean passedSlop = mGestureState.isTrackpadGesture()
+ || (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop
+ && !mGestureState.isInExtendedSlopRegion());
if (!mPassedSlopOnThisGesture && passedSlop) {
mPassedSlopOnThisGesture = true;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index bb8d1d7..c61f71d 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -48,6 +48,7 @@
private final BaseContainerInterface<?, T> mContainerInterface;
private final BaseDragLayer mTarget;
private final InputMonitorCompat mInputMonitor;
+ private final GestureState mGestureState;
private final int[] mLocationOnScreen = new int[2];
@@ -62,6 +63,7 @@
mInputMonitor = inputMonitor;
mStartingInActivityBounds = startingInActivityBounds;
mContainerInterface = gestureState.getContainerInterface();
+ mGestureState = gestureState;
mTarget = container.getDragLayer();
mTarget.getLocationOnScreen(mLocationOnScreen);
@@ -84,7 +86,10 @@
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
}
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
- boolean handled = mTarget.proxyTouchEvent(ev, mStartingInActivityBounds);
+ boolean handled = false;
+ if (mGestureState == null || !mGestureState.isInExtendedSlopRegion()) {
+ handled = mTarget.proxyTouchEvent(ev, mStartingInActivityBounds);
+ }
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
ev.setEdgeFlags(flags);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index cd180ba..9a25c32 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -28,6 +28,8 @@
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -42,6 +44,7 @@
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.systemui.shared.system.InputMonitorCompat;
@@ -51,6 +54,9 @@
*/
public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
+ private static final int HOVER_TASKBAR_UNSTASH_TIMEOUT = 500;
+ private static final Handler sUnstashHandler = new Handler(Looper.getMainLooper());
+
private final TaskbarActivityContext mTaskbarActivityContext;
private final OverviewCommandHelper mOverviewCommandHelper;
private final float mUnstashArea;
@@ -76,10 +82,11 @@
private final int mStashedTaskbarBottomEdge;
private final @Nullable TransitionCallback mTransitionCallback;
+ private final GestureState mGestureState;
public TaskbarUnstashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext,
- OverviewCommandHelper overviewCommandHelper) {
+ OverviewCommandHelper overviewCommandHelper, GestureState gestureState) {
super(delegate, inputMonitor);
mTaskbarActivityContext = taskbarActivityContext;
mOverviewCommandHelper = overviewCommandHelper;
@@ -103,6 +110,7 @@
mTransitionCallback = mIsTransientTaskbar
? taskbarActivityContext.getTranslationCallbacks()
: null;
+ mGestureState = gestureState;
}
@Override
@@ -111,6 +119,11 @@
}
@Override
+ public boolean allowInterceptByParent() {
+ return super.allowInterceptByParent() && !mHasPassedTaskbarNavThreshold;
+ }
+
+ @Override
public void onMotionEvent(MotionEvent ev) {
if (mState != STATE_ACTIVE) {
boolean isStashedTaskbarHovered = isMouseEvent(ev)
@@ -173,7 +186,8 @@
boolean passedTaskbarNavThreshold = dY < 0
&& Math.abs(dY) >= mTaskbarNavThreshold;
- if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) {
+ if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold
+ && !mGestureState.isInExtendedSlopRegion()) {
mHasPassedTaskbarNavThreshold = true;
if (mIsInBubbleBarArea && mIsVerticalGestureOverBubbleBar) {
mTaskbarActivityContext.onSwipeToOpenBubblebar();
@@ -299,16 +313,25 @@
dp.heightPx);
if (mBottomEdgeBounds.contains(x, y)) {
- // If hovering stashed taskbar and then hover screen bottom edge, unstash it.
- mTaskbarActivityContext.onSwipeToUnstashTaskbar();
- mIsStashedTaskbarHovered = false;
+ // start a single unstash timeout if hovering bottom edge under the hinted taskbar.
+ if (!sUnstashHandler.hasMessagesOrCallbacks()) {
+ sUnstashHandler.postDelayed(() -> {
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ mIsStashedTaskbarHovered = false;
+ }, HOVER_TASKBAR_UNSTASH_TIMEOUT);
+ }
} else if (!isStashedTaskbarHovered(x, y)) {
- // If exit hovering stashed taskbar, remove hint.
+ // If exit hovering stashed taskbar, remove hint and clear pending unstash calls.
+ sUnstashHandler.removeCallbacksAndMessages(null);
startStashedTaskbarHover(/* isHovered = */ false);
+ } else {
+ sUnstashHandler.removeCallbacksAndMessages(null);
}
}
private void updateUnhoveredTaskbarState(int x, int y) {
+ sUnstashHandler.removeCallbacksAndMessages(null);
+
DeviceProfile dp = mTaskbarActivityContext.getDeviceProfile();
mBottomEdgeBounds.set(
0,
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index d5cc447..ad13efb 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -382,7 +382,7 @@
}
@Override
- public void update(RectF rect, float progress, float radius) {
+ public void update(RectF rect, float progress, float radius, int overlayAlpha) {
mFakeIconView.setVisibility(View.VISIBLE);
mFakeIconView.update(rect, progress,
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index a09e027..3cae4dc 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -58,10 +58,6 @@
import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
-import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LogConfig;
@@ -347,7 +343,6 @@
event.getId() + "";
Log.d(TAG, name);
}
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
if (mSlice == null && mSliceItem != null) {
mSlice = LauncherAtom.Slice.newBuilder().setUri(
@@ -369,25 +364,17 @@
return;
}
- if (mItemInfo.container < 0 || appState == null) {
+ if (mItemInfo.container < 0 || !LauncherAppState.INSTANCE.executeIfCreated(app -> {
+ // Item is inside a collection, fetch collection info in a BG thread
+ // and then write to StatsLog.
+ app.getModel().enqueueModelUpdateTask((taskController, dataModel, apps) ->
+ write(event, applyOverwrites(mItemInfo.buildProto(
+ dataModel.collections.get(mItemInfo.container)))));
+ })) {
// Write log on the model thread so that logs do not go out of order
// (for eg: drop comes after drag)
Executors.MODEL_EXECUTOR.execute(
() -> write(event, applyOverwrites(mItemInfo.buildProto())));
- } else {
- // Item is inside a collection, fetch collection info in a BG thread
- // and then write to StatsLog.
- appState.getModel().enqueueModelUpdateTask(
- new BaseModelUpdateTask() {
- @Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList apps) {
- CollectionInfo collectionInfo =
- dataModel.collections.get(mItemInfo.container);
- write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
- }
- });
}
}
@@ -405,6 +392,20 @@
case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END:
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL);
break;
+ case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN:
+ InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
+ break;
+ case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END:
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
+ break;
+ case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN:
+ InteractionJankMonitorWrapper.begin(
+ view,
+ Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
+ break;
+ case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END:
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
+ break;
default:
break;
}
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt
new file mode 100644
index 0000000..28212cf
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.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.quickstep.recents.viewmodel
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+// This is far from complete but serves the purpose of enabling refactoring in other areas
+class RecentsViewData {
+ val fullscreenProgress = MutableStateFlow(1f)
+
+ // This is typically a View concern but it is used to invalidate rendering in other Views
+ val scale = MutableStateFlow(1f)
+}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
new file mode 100644
index 0000000..0843ae3
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import com.android.systemui.shared.recents.model.Task
+
+sealed class TaskThumbnailUiState {
+ data object Uninitialized : TaskThumbnailUiState()
+ data object LiveTile : TaskThumbnailUiState()
+}
+
+data class TaskThumbnail(val task: Task, val isRunning: Boolean)
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
new file mode 100644
index 0000000..b466f3f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -0,0 +1,129 @@
+/*
+ * 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.content.Context
+import android.content.res.Configuration
+import android.graphics.Canvas
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewOutlineProvider
+import com.android.launcher3.Utilities
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
+import com.android.quickstep.util.TaskCornerRadius
+import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.RecentsViewContainer
+import com.android.quickstep.views.TaskView
+import com.android.systemui.shared.system.QuickStepContract
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.launch
+
+class TaskThumbnailView : View {
+ // TODO(b/335649589): Ideally create and obtain this from DI. This ViewModel should be scoped
+ // to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
+ // This is using a lazy for now because the dependencies cannot be obtained without DI.
+ val viewModel by lazy {
+ TaskThumbnailViewModel(
+ RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
+ .getOverviewPanel<RecentsView<*, *>>()
+ .mRecentsViewData,
+ (parent as TaskView).mTaskViewData
+ )
+ }
+
+ private var uiState: TaskThumbnailUiState = Uninitialized
+ private var inheritedScale: Float = 1f
+
+ private var cornerRadius: Float = TaskCornerRadius.get(context)
+ private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
+
+ 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 onAttachedToWindow() {
+ super.onAttachedToWindow()
+ // TODO(b/335396935) replace MainScope with shorter lifecycle.
+ MainScope().launch {
+ viewModel.uiState.collect { viewModelUiState ->
+ uiState = viewModelUiState
+ invalidate()
+ }
+ }
+ MainScope().launch { viewModel.recentsFullscreenProgress.collect { invalidateOutline() } }
+ MainScope().launch {
+ viewModel.inheritedScale.collect { viewModelInheritedScale ->
+ inheritedScale = viewModelInheritedScale
+ invalidateOutline()
+ }
+ }
+
+ clipToOutline = true
+ outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View, outline: Outline) {
+ outline.setRoundRect(
+ 0,
+ 0,
+ view.measuredWidth,
+ view.measuredHeight,
+ getCurrentCornerRadius()
+ )
+ }
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ when (uiState) {
+ is Uninitialized -> {}
+ is LiveTile -> drawTransparentUiState(canvas)
+ }
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration?) {
+ super.onConfigurationChanged(newConfig)
+
+ cornerRadius = TaskCornerRadius.get(context)
+ fullscreenCornerRadius = QuickStepContract.getWindowCornerRadius(context)
+ invalidateOutline()
+ }
+
+ private fun drawTransparentUiState(canvas: Canvas) {
+ canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
+ }
+
+ private fun getCurrentCornerRadius() =
+ Utilities.mapRange(
+ viewModel.recentsFullscreenProgress.value,
+ cornerRadius,
+ fullscreenCornerRadius
+ ) / inheritedScale
+
+ companion object {
+ private val CLEAR_PAINT =
+ Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
new file mode 100644
index 0000000..71bc865
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
+import com.android.quickstep.task.viewmodel.TaskViewData
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+class TaskThumbnailViewModel(recentsViewData: RecentsViewData, taskViewData: TaskViewData) {
+ private val task = MutableStateFlow<TaskThumbnail?>(null)
+
+ val recentsFullscreenProgress = recentsViewData.fullscreenProgress
+ val inheritedScale =
+ combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
+ recentsScale * taskScale
+ }
+ val uiState =
+ task.map { taskVal ->
+ when {
+ taskVal == null -> Uninitialized
+ taskVal.isRunning -> LiveTile
+ else -> Uninitialized
+ }
+ }
+
+ fun bind(task: TaskThumbnail) {
+ this.task.value = task
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
new file mode 100644
index 0000000..a8b5112
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskViewData.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.viewmodel
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class TaskViewData {
+ // This is typically a View concern but it is used to invalidate rendering in other Views
+ val scale = MutableStateFlow(1f)
+}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 2b4d280..e4e2eb2 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -22,6 +22,7 @@
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_PAIR_LAUNCH;
import static com.android.launcher3.model.data.AppInfo.PACKAGE_KEY_COMPARATOR;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SUPPORTS_MULTI_INSTANCE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -32,34 +33,38 @@
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
import android.util.Log;
import android.util.Pair;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.Cuj;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.apppairs.AppPairIcon;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.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.taskbar.TaskbarActivityContext;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.TaskView;
@@ -101,6 +106,55 @@
}
/**
+ * Returns whether the specified GroupedTaskView can be saved as an app pair.
+ */
+ public boolean canSaveAppPair(TaskView taskView) {
+ if (mContext == null) {
+ // Can ignore as the activity is already destroyed
+ return false;
+ }
+
+ // Disallow saving app pairs if:
+ // - app pairs feature is not enabled
+ // - the task in question is a single task
+ // - at least one app in app pair is unpinnable
+ // - the task is not a GroupedTaskView
+ // - both tasks in the GroupedTaskView are from the same app and the app does not
+ // support multi-instance
+ boolean hasUnpinnableApp = taskView.getTaskContainers().stream()
+ .anyMatch(att -> att != null && att.getItemInfo() != null
+ && ((att.getItemInfo().runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
+ if (!FeatureFlags.enableAppPairs()
+ || !taskView.containsMultipleTasks()
+ || hasUnpinnableApp
+ || !(taskView instanceof GroupedTaskView)) {
+ return false;
+ }
+
+ GroupedTaskView gtv = (GroupedTaskView) taskView;
+ List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
+ ComponentKey taskKey1 = TaskUtils.getLaunchComponentKeyForTask(
+ containers.get(0).getTask().key);
+ ComponentKey taskKey2 = TaskUtils.getLaunchComponentKeyForTask(
+ containers.get(1).getTask().key);
+ AppInfo app1 = resolveAppInfoByComponent(taskKey1);
+ AppInfo app2 = resolveAppInfoByComponent(taskKey2);
+
+ if (app1 == null || app2 == null) {
+ // Disallow saving app pairs for apps that don't have a front-door in Launcher
+ return false;
+ }
+
+ if (PackageManagerHelper.isSameAppForMultiInstance(app1, app2)) {
+ if (!app1.supportsMultiInstance() || !app2.supportsMultiInstance()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Creates a new app pair ItemInfo and adds it to the workspace.
* <br>
* We create WorkspaceItemInfos to save onto the app pair in the following way:
@@ -116,34 +170,26 @@
*/
public void saveAppPair(GroupedTaskView gtv) {
InteractionJankMonitorWrapper.begin(gtv, Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
- TaskView.TaskIdAttributeContainer[] attributes = gtv.getTaskIdAttributeContainers();
- WorkspaceItemInfo recentsInfo1 = attributes[0].getItemInfo();
- WorkspaceItemInfo recentsInfo2 = attributes[1].getItemInfo();
- WorkspaceItemInfo app1 = lookupLaunchableItem(recentsInfo1.getComponentKey());
- WorkspaceItemInfo app2 = lookupLaunchableItem(recentsInfo2.getComponentKey());
+ List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
+ WorkspaceItemInfo recentsInfo1 = containers.get(0).getItemInfo();
+ WorkspaceItemInfo recentsInfo2 = containers.get(1).getItemInfo();
+ WorkspaceItemInfo app1 = resolveAppPairWorkspaceInfo(recentsInfo1);
+ WorkspaceItemInfo app2 = resolveAppPairWorkspaceInfo(recentsInfo2);
- // If app lookup fails, use the WorkspaceItemInfo that we have, but try to override default
- // intent with one from PackageManager.
- if (app1 == null) {
- Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo1.title
- + " failed. Falling back to the WorkspaceItemInfo from Recents.");
- app1 = convertRecentsItemToAppItem(recentsInfo1);
+ if (app1 == null || app2 == null) {
+ // This shouldn't happen if canSaveAppPair() is called above, but log an error and do
+ // not create the app pair if the workspace items can't be resolved
+ Log.w(TAG, "Failed to save app pair due to invalid apps ("
+ + "app1=" + recentsInfo1.getComponentKey().componentName
+ + " app2=" + recentsInfo2.getComponentKey().componentName + ")");
+ return;
}
- if (app2 == null) {
- Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo2.title
- + " failed. Falling back to the WorkspaceItemInfo from Recents.");
- app2 = convertRecentsItemToAppItem(recentsInfo2);
- }
-
- // WorkspaceItemProcessor won't process these new ItemInfos until the next launcher restart,
- // so update some flags now.
- updateWorkspaceItemFlags(app1);
- updateWorkspaceItemFlags(app2);
@PersistentSnapPosition int snapPosition = gtv.getSnapPosition();
if (!isPersistentSnapPosition(snapPosition)) {
- // if we received an illegal snap position, log an error and do not create the app pair.
- Log.wtf(TAG, "tried to save an app pair with illegal snapPosition " + snapPosition);
+ // If we received an illegal snap position, log an error and do not create the app pair
+ Log.wtf(TAG, "Tried to save an app pair with illegal snapPosition "
+ + snapPosition);
return;
}
@@ -229,67 +275,38 @@
}
/**
+ * Returns an AppInfo associated with the app for the given ComponentKey, or null if no such
+ * package exists in the AllAppsStore.
+ */
+ @Nullable
+ private AppInfo resolveAppInfoByComponent(@NonNull ComponentKey key) {
+ AllAppsStore appsStore = ActivityContext.lookupContext(mContext)
+ .getAppsView().getAppsStore();
+
+ // First look up the app info in order of:
+ // - The exact activity for the recent task
+ // - The first(?) loaded activity from the package
+ AppInfo appInfo = appsStore.getApp(key);
+ if (appInfo == null) {
+ appInfo = appsStore.getApp(key, PACKAGE_KEY_COMPARATOR);
+ }
+ return appInfo;
+ }
+
+ /**
* Creates a new launchable WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION by looking the
* ComponentKey up in the AllAppsStore. If no app is found, attempts a lookup by package
* instead. If that lookup fails, returns null.
*/
@Nullable
- private WorkspaceItemInfo lookupLaunchableItem(@Nullable ComponentKey key) {
- if (key == null) {
+ private WorkspaceItemInfo resolveAppPairWorkspaceInfo(
+ @NonNull WorkspaceItemInfo recentTaskInfo) {
+ // ComponentKey should never be null (see TaskView#getItemInfo)
+ AppInfo appInfo = resolveAppInfoByComponent(recentTaskInfo.getComponentKey());
+ if (appInfo == null) {
return null;
}
-
- AllAppsStore appsStore = ActivityContext.lookupContext(mContext)
- .getAppsView().getAppsStore();
-
- // Lookup by ComponentKey
- AppInfo appInfo = appsStore.getApp(key);
- if (appInfo == null) {
- // Lookup by package
- appInfo = appsStore.getApp(key, PACKAGE_KEY_COMPARATOR);
- }
-
- return appInfo != null ? appInfo.makeWorkspaceItem(mContext) : null;
- }
-
- /**
- * Updates flags for newly created WorkspaceItemInfos.
- */
- private void updateWorkspaceItemFlags(WorkspaceItemInfo wii) {
- PackageManager pm = mContext.getPackageManager();
- ActivityInfo ai = null;
- try {
- ai = pm.getActivityInfo(wii.getTargetComponent(), 0);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "PackageManager lookup failed.");
- }
-
- if (ai != null) {
- wii.setNonResizeable(ai.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE);
- }
- }
-
- /**
- * Converts a WorkspaceItemInfo of itemType=ITEM_TYPE_TASK (from a Recents task) to a new
- * WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION.
- */
- private WorkspaceItemInfo convertRecentsItemToAppItem(WorkspaceItemInfo recentsItem) {
- if (recentsItem.itemType != LauncherSettings.Favorites.ITEM_TYPE_TASK) {
- Log.w(TAG, "Expected ItemInfo of type ITEM_TYPE_TASK, but received "
- + recentsItem.itemType);
- }
-
- WorkspaceItemInfo launchableItem = recentsItem.clone();
- PackageManager p = mContext.getPackageManager();
- Intent launchIntent = p.getLaunchIntentForPackage(recentsItem.getTargetPackage());
- Log.w(TAG, "Initial intent from Recents: " + launchableItem.intent + "\n"
- + "Intent from PackageManager: " + launchIntent);
- if (launchIntent != null) {
- // If lookup from PackageManager fails, just use the existing intent
- launchableItem.intent = launchIntent;
- }
- launchableItem.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
- return launchableItem;
+ return appInfo.makeWorkspaceItem(mContext);
}
/**
@@ -316,7 +333,7 @@
itemInfos.stream().map(ItemInfo::getComponentKey).toList();
// Use TopTaskTracker to find the currently running app (or apps)
- TopTaskTracker topTaskTracker = getTopTaskTracker(context);
+ TopTaskTracker topTaskTracker = getTopTaskTracker();
// getRunningSplitTasksIds() will return a pair of ids if we are currently running a
// split pair, or an empty array with zero length if we are running a single app.
@@ -489,7 +506,7 @@
* Gets the TopTaskTracker, which is a cached record of the top running Task.
*/
@VisibleForTesting
- public TopTaskTracker getTopTaskTracker(Context context) {
- return TopTaskTracker.INSTANCE.get(context);
+ public TopTaskTracker getTopTaskTracker() {
+ return TopTaskTracker.INSTANCE.get(mContext);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
index 4a35c3b..7acb28d 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -33,13 +33,8 @@
public AssistStateManager() {}
- /** Whether search supports haptic on invocation. */
- public boolean supportsCommitHaptic() {
- return false;
- }
-
- /** Whether search is available. */
- public boolean isSearchAvailable() {
+ /** Return {@code true} if the Settings toggle is enabled. */
+ public boolean isSettingsAllEntrypointsEnabled() {
return false;
}
@@ -48,14 +43,9 @@
return false;
}
- /** Whether CsHelper CtS invocation path is available. */
- public Optional<Boolean> isCsHelperAvailable() {
- return Optional.empty();
- }
-
- /** Whether VIS CtS invocation path is available. */
- public Optional<Boolean> isVisAvailable() {
- return Optional.empty();
+ /** Whether ContextualSearchService invocation path is available. */
+ public boolean isContextualSearchServiceAvailable() {
+ return false;
}
/** Get the Launcher overridden long press nav handle duration to trigger Assistant. */
@@ -90,9 +80,9 @@
return 0;
}
- /** Return {@code true} if the Settings toggle is enabled. */
- public boolean isSettingsAllEntrypointsEnabled() {
- return false;
+ /** Get the haptic bit overridden by AGSA. */
+ public Optional<Boolean> getShouldPlayHapticOverride() {
+ return Optional.empty();
}
/** Dump states. */
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java
index b3f5d82..07f2d68 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.java
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.java
@@ -56,4 +56,10 @@
public DesktopTask copy() {
return new DesktopTask(tasks);
}
+
+ @Override
+ public String toString() {
+ return "type=" + taskViewType + " tasks=" + tasks;
+ }
+
}
diff --git a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
index 544c64d..d36dc7e 100644
--- a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
+++ b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
@@ -48,12 +48,14 @@
PropReader(
object : PropProvider {
override fun <T : Any> get(key: String, fallback: T): T {
- if (fallback is Int)
+ if (fallback is Int) {
+ allKeys.add(key)
return DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, fallback) as T
- else if (fallback is Boolean)
+ } else if (fallback is Boolean) {
+ allKeys.add(key)
return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, fallback)
as T
- else return fallback
+ } else return fallback
}
}
)
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
index 9c49647..7dd6afc 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.java
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.java
@@ -70,4 +70,10 @@
task2 != null ? new Task(task2) : null,
mSplitBounds);
}
+
+ @Override
+ public String toString() {
+ return "type=" + taskViewType + " task1=" + task1 + " task2=" + task2;
+ }
+
}
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 9df568e..2a27dea 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -136,21 +136,16 @@
});
}
- if (!ALL_APPS_VISITED_COUNT.hasReachedMax(launcher)) {
+ if (!Utilities.isRunningInTestHarness()) {
launcher.getStateManager().addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == ALL_APPS) {
ALL_APPS_VISITED_COUNT.increment(launcher);
- return;
}
-
- boolean hasReachedMaxCount = ALL_APPS_VISITED_COUNT.hasReachedMax(launcher);
- launcher.getAppsView().getFloatingHeaderView().findFixedRowByType(
- AppsDividerView.class).setShowAllAppsLabel(!hasReachedMaxCount);
- if (hasReachedMaxCount) {
- launcher.getStateManager().removeStateListener(this);
- }
+ launcher.getAppsView().getFloatingHeaderView()
+ .findFixedRowByType(AppsDividerView.class)
+ .setShowAllAppsLabel(!ALL_APPS_VISITED_COUNT.hasReachedMax(launcher));
}
});
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 021c455..40ea70f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -23,6 +23,7 @@
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.content.Context
import android.graphics.Bitmap
@@ -50,6 +51,7 @@
import com.android.launcher3.apppairs.AppPairIcon
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.logging.StatsLogManager.EventEnum
+import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.taskbar.TaskbarActivityContext
@@ -65,10 +67,11 @@
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.SplitInstructionsView
-import com.android.quickstep.views.TaskThumbnailView
+import com.android.quickstep.views.TaskThumbnailViewDeprecated
import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
import com.android.quickstep.views.TaskViewIcon
+import com.android.wm.shell.shared.TransitionUtil
import java.util.Optional
import java.util.function.Supplier
@@ -111,7 +114,7 @@
} else if (splitSelectStateController.isDismissingFromSplitPair) {
// Initiating split from overview, but on a split pair
val taskView = taskViewSupplier.get()
- for (container: TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
+ for (container: TaskContainer in taskView.taskContainers) {
if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) {
val drawable = getDrawable(container.iconView, splitSelectSource)
return SplitAnimInitProps(
@@ -131,15 +134,17 @@
} else {
// Initiating split from overview on fullscreen task TaskView
val taskView = taskViewSupplier.get()
- val drawable = getDrawable(taskView.iconView, splitSelectSource)
- return SplitAnimInitProps(
- taskView.thumbnail,
- taskView.thumbnail.thumbnail,
- drawable!!,
- fadeWithThumbnail = true,
- isStagedTask = true,
- taskView.iconView.asView()
- )
+ taskView.taskContainers.first().let {
+ val drawable = getDrawable(it.iconView, splitSelectSource)
+ return SplitAnimInitProps(
+ it.thumbnailView,
+ it.thumbnailView.thumbnail,
+ drawable!!,
+ fadeWithThumbnail = true,
+ isStagedTask = true,
+ iconView = it.iconView.asView()
+ )
+ }
}
}
@@ -160,9 +165,9 @@
/**
* When selecting first app from split pair, second app's thumbnail remains. This animates the
* second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying it
- * with [TaskThumbnailView]'s splashView. Adds animations to the provided builder. Note: The app
- * that **was not** selected as the first split app should be the container that's passed
- * through.
+ * with [TaskThumbnailViewDeprecated]'s splashView. Adds animations to the provided builder.
+ * Note: The app that **was not** selected as the first split app should be the container that's
+ * passed through.
*
* @param builder Adds animation to this
* @param taskIdAttributeContainer container of the app that **was not** selected
@@ -170,7 +175,7 @@
* (opposite of that representing [taskIdAttributeContainer])
*/
fun addInitialSplitFromPair(
- taskIdAttributeContainer: TaskIdAttributeContainer,
+ taskIdAttributeContainer: TaskContainer,
builder: PendingAnimation,
deviceProfile: DeviceProfile,
taskViewWidth: Int,
@@ -179,7 +184,7 @@
) {
val thumbnail = taskIdAttributeContainer.thumbnailView
val iconView: View = taskIdAttributeContainer.iconView.asView()
- builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
+ builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailViewDeprecated.SPLASH_ALPHA, 1f))
thumbnail.setShowSplashForSplitSelection(true)
// With the new `IconAppChipView`, we always want to keep the chip pinned to the
// top left of the task / thumbnail.
@@ -202,7 +207,7 @@
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
- TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X,
+ TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
centerThumbnailTranslationX
)
)
@@ -224,7 +229,7 @@
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
- TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+ TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
translateYResetVal
)
)
@@ -252,7 +257,7 @@
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
- TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+ TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
centerThumbnailTranslationY
)
)
@@ -266,7 +271,11 @@
// Reset other dimensions
thumbnail.scaleX = 1f
builder.add(
- ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f)
+ ObjectAnimator.ofFloat(
+ thumbnail,
+ TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
+ 0f
+ )
)
}
}
@@ -276,43 +285,59 @@
* [pendingAnimation]. Assumes that animation will be the final split placeholder launch anim.
*
* [secondPlaceholderEndingBounds] refers to the second placeholder view that gets added on
- * screen, not the logical second app.
- * For landscape it's the left app and for portrait the top one.
+ * screen, not the logical second app. For landscape it's the left app and for portrait the top
+ * one.
*/
- fun addDividerPlaceholderViewToAnim(pendingAnimation: PendingAnimation,
- container: RecentsViewContainer,
- secondPlaceholderEndingBounds: Rect,
- context: Context) : View {
+ fun addDividerPlaceholderViewToAnim(
+ pendingAnimation: PendingAnimation,
+ container: RecentsViewContainer,
+ secondPlaceholderEndingBounds: Rect,
+ context: Context
+ ): View {
val mSplitDividerPlaceholderView = View(context)
val recentsView = container.getOverviewPanel<RecentsView<*, *>>()
- val dp : com.android.launcher3.DeviceProfile = container.getDeviceProfile()
+ val dp: com.android.launcher3.DeviceProfile = container.getDeviceProfile()
// Add it before/under the most recently added first floating taskView
- val firstAddedSplitViewIndex: Int = container.getDragLayer().indexOfChild(
- recentsView.splitSelectController.firstFloatingTaskView)
+ val firstAddedSplitViewIndex: Int =
+ container
+ .getDragLayer()
+ .indexOfChild(recentsView.splitSelectController.firstFloatingTaskView)
container.getDragLayer().addView(mSplitDividerPlaceholderView, firstAddedSplitViewIndex)
val lp = mSplitDividerPlaceholderView.layoutParams as InsettableFrameLayout.LayoutParams
lp.topMargin = 0
if (dp.isLeftRightSplit) {
lp.height = secondPlaceholderEndingBounds.height()
- lp.width = container.asContext().resources.
- getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
- mSplitDividerPlaceholderView.translationX = secondPlaceholderEndingBounds.right - lp.width / 2f
+ lp.width =
+ container
+ .asContext()
+ .resources
+ .getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
+ mSplitDividerPlaceholderView.translationX =
+ secondPlaceholderEndingBounds.right - lp.width / 2f
mSplitDividerPlaceholderView.translationY = 0f
} else {
- lp.height = container.asContext().resources
+ lp.height =
+ container
+ .asContext()
+ .resources
.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
lp.width = secondPlaceholderEndingBounds.width()
- mSplitDividerPlaceholderView.translationY = secondPlaceholderEndingBounds.top - lp.height / 2f
+ mSplitDividerPlaceholderView.translationY =
+ secondPlaceholderEndingBounds.top - lp.height / 2f
mSplitDividerPlaceholderView.translationX = 0f
}
mSplitDividerPlaceholderView.alpha = 0f
- mSplitDividerPlaceholderView.setBackgroundColor(container.asContext().resources
- .getColor(R.color.taskbar_background_dark))
+ mSplitDividerPlaceholderView.setBackgroundColor(
+ container.asContext().resources.getColor(R.color.taskbar_background_dark)
+ )
val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet)
- pendingAnimation.setViewAlpha(mSplitDividerPlaceholderView, 1f,
- Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f))
+ pendingAnimation.setViewAlpha(
+ mSplitDividerPlaceholderView,
+ 1f,
+ Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f)
+ )
return mSplitDividerPlaceholderView
}
@@ -533,8 +558,19 @@
check(info != null && t != null) {
"trying to launch an app pair icon, but encountered an unexpected null"
}
-
- composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback)
+ val appPairLaunchingAppIndex = hasChangesForBothAppPairs(launchingIconView, info)
+ if (appPairLaunchingAppIndex == -1) {
+ // Launch split app pair animation
+ composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback)
+ } else {
+ composeFullscreenIconSplitLaunchAnimator(
+ launchingIconView,
+ info,
+ t,
+ finishCallback,
+ appPairLaunchingAppIndex
+ )
+ }
} else {
// Fallback case: simple fade-in animation
check(info != null && t != null) {
@@ -599,6 +635,43 @@
}
/**
+ * @return -1 if [transitionInfo] contains both apps of the app pair to be animated, otherwise
+ * the integer index corresponding to [launchingIconView]'s contents for the single app to be
+ * animated
+ */
+ fun hasChangesForBothAppPairs(
+ launchingIconView: AppPairIcon,
+ transitionInfo: TransitionInfo
+ ): Int {
+ val intent1 = launchingIconView.info.getFirstApp().intent.component?.packageName
+ val intent2 = launchingIconView.info.getSecondApp().intent.component?.packageName
+ var launchFullscreenAppIndex = -1
+ for (change in transitionInfo.changes) {
+ val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
+ if (
+ TransitionUtil.isOpeningType(change.mode) &&
+ taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN
+ ) {
+ val baseIntent = taskInfo.baseIntent.component?.packageName
+ if (baseIntent == intent1) {
+ if (launchFullscreenAppIndex > -1) {
+ launchFullscreenAppIndex = -1
+ break
+ }
+ launchFullscreenAppIndex = 0
+ } else if (baseIntent == intent2) {
+ if (launchFullscreenAppIndex > -1) {
+ launchFullscreenAppIndex = -1
+ break
+ }
+ launchFullscreenAppIndex = 1
+ }
+ }
+ }
+ return launchFullscreenAppIndex
+ }
+
+ /**
* When the user taps an app pair icon to launch split, this will play the tasks' launch
* animation from the position of the icon.
*
@@ -633,7 +706,12 @@
// If launching an app pair from Taskbar inside of an app context (no access to Launcher),
// use the scale-up animation
if (launchingIconView.context is TaskbarActivityContext) {
- composeScaleUpLaunchAnimation(transitionInfo, t, finishCallback)
+ composeScaleUpLaunchAnimation(
+ transitionInfo,
+ t,
+ finishCallback,
+ WINDOWING_MODE_MULTI_WINDOW
+ )
return
}
@@ -643,11 +721,6 @@
// Create an AnimatorSet that will run both shell and launcher transitions together
val launchAnimation = AnimatorSet()
- val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
- val timings = AnimUtils.getDeviceAppPairLaunchTimings(dp.isTablet)
- progressUpdater.setDuration(timings.getDuration().toLong())
- progressUpdater.interpolator = Interpolators.LINEAR
-
var rootCandidate: Change? = null
for (change in transitionInfo.changes) {
@@ -691,6 +764,122 @@
// Make sure nothing weird happened, like getChange() returning null.
check(rootCandidate != null) { "Failed to find a root leash" }
+ // Create a new floating view in Launcher, positioned above the launching icon
+ val drawableArea = launchingIconView.iconDrawableArea
+ val appIcon1 = launchingIconView.info.getFirstApp().newIcon(launchingIconView.context)
+ val appIcon2 = launchingIconView.info.getSecondApp().newIcon(launchingIconView.context)
+ appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+ appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+
+ val floatingView =
+ FloatingAppPairView.getFloatingAppPairView(
+ launcher,
+ drawableArea,
+ appIcon1,
+ appIcon2,
+ dividerPos
+ )
+ floatingView.bringToFront()
+
+ launchAnimation.play(
+ getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView, rootCandidate)
+ )
+ launchAnimation.start()
+ }
+
+ /**
+ * Similar to [composeIconSplitLaunchAnimator], but instructs [FloatingAppPairView] to animate a
+ * single fullscreen icon + background instead of for a pair
+ */
+ @VisibleForTesting
+ fun composeFullscreenIconSplitLaunchAnimator(
+ launchingIconView: AppPairIcon,
+ transitionInfo: TransitionInfo,
+ t: Transaction,
+ finishCallback: Runnable,
+ launchFullscreenIndex: Int
+ ) {
+ // If launching an app pair from Taskbar inside of an app context (no access to Launcher),
+ // use the scale-up animation
+ if (launchingIconView.context is TaskbarActivityContext) {
+ composeScaleUpLaunchAnimation(
+ transitionInfo,
+ t,
+ finishCallback,
+ WINDOWING_MODE_FULLSCREEN
+ )
+ return
+ }
+
+ // Else we are in Launcher and can launch with the full icon stretch-and-split animation.
+ val launcher = QuickstepLauncher.getLauncher(launchingIconView.context)
+ val dp = launcher.deviceProfile
+
+ // Create an AnimatorSet that will run both shell and launcher transitions together
+ val launchAnimation = AnimatorSet()
+
+ val appInfo =
+ launchingIconView.info.getContents()[launchFullscreenIndex] as WorkspaceItemInfo
+ val intentToLaunch = appInfo.intent.component?.packageName
+ var rootCandidate: Change? = null
+ for (change in transitionInfo.changes) {
+ val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
+ val baseIntent = taskInfo.baseIntent.component?.packageName
+ if (
+ TransitionUtil.isOpeningType(change.mode) &&
+ taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN &&
+ baseIntent == intentToLaunch
+ ) {
+ rootCandidate = change
+ }
+ }
+
+ // If we could not find a proper root candidate, something went wrong.
+ check(rootCandidate != null) { "Could not find a split root candidate" }
+
+ // Recurse up the tree until parent is null, then we've found our root.
+ var parentToken: WindowContainerToken? = rootCandidate.parent
+ while (parentToken != null) {
+ rootCandidate = transitionInfo.getChange(parentToken) ?: break
+ parentToken = rootCandidate.parent
+ }
+
+ // Make sure nothing weird happened, like getChange() returning null.
+ check(rootCandidate != null) { "Failed to find a root leash" }
+
+ // Create a new floating view in Launcher, positioned above the launching icon
+ val drawableArea = launchingIconView.iconDrawableArea
+ val appIcon = appInfo.newIcon(launchingIconView.context)
+ appIcon.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+
+ val floatingView =
+ FloatingAppPairView.getFloatingAppPairView(
+ launcher,
+ drawableArea,
+ appIcon,
+ null /*appIcon2*/,
+ 0 /*dividerPos*/
+ )
+ floatingView.bringToFront()
+ launchAnimation.play(
+ getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView, rootCandidate)
+ )
+ launchAnimation.start()
+ }
+
+ private fun getIconLaunchValueAnimator(
+ t: Transaction,
+ dp: com.android.launcher3.DeviceProfile,
+ finishCallback: Runnable,
+ launcher: QuickstepLauncher,
+ floatingView: FloatingAppPairView,
+ rootCandidate: Change
+ ): ValueAnimator {
+ val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
+ val timings = AnimUtils.getDeviceAppPairLaunchTimings(dp.isTablet)
+ progressUpdater.setDuration(timings.getDuration().toLong())
+ progressUpdater.interpolator = Interpolators.LINEAR
+
// Shell animation: the apps are revealed toward end of the launch animation
progressUpdater.addUpdateListener { valueAnimator: ValueAnimator ->
val progress =
@@ -706,23 +895,6 @@
t.apply()
}
- // Create a new floating view in Launcher, positioned above the launching icon
- val drawableArea = launchingIconView.iconDrawableArea
- val appIcon1 = launchingIconView.info.getFirstApp().newIcon(launchingIconView.context)
- val appIcon2 = launchingIconView.info.getSecondApp().newIcon(launchingIconView.context)
- appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
- appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
- val floatingView =
- FloatingAppPairView.getFloatingAppPairView(
- launcher,
- drawableArea,
- appIcon1,
- appIcon2,
- dividerPos
- )
- floatingView.bringToFront()
-
- // Launcher animation: animate the floating view, expanding to fill the display surface
progressUpdater.addUpdateListener(
object : MultiValueUpdateListener() {
var mDx =
@@ -776,8 +948,6 @@
}
}
)
-
- // When animation ends, remove the floating view and run finishCallback
progressUpdater.addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
@@ -787,19 +957,20 @@
}
)
- launchAnimation.play(progressUpdater)
- launchAnimation.start()
+ return progressUpdater
}
/**
* This is a scale-up-and-fade-in animation (34% to 100%) for launching an app in Overview when
- * there is no visible associated tile to expand from.
+ * there is no visible associated tile to expand from. [windowingMode] helps determine whether
+ * we are looking for a split or a single fullscreen [Change]
*/
@VisibleForTesting
fun composeScaleUpLaunchAnimation(
transitionInfo: TransitionInfo,
t: Transaction,
- finishCallback: Runnable
+ finishCallback: Runnable,
+ windowingMode: Int
) {
val launchAnimation = AnimatorSet()
val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
@@ -813,9 +984,8 @@
// TODO (b/316490565): Replace this logic when SplitBounds is available to
// startAnimation() and we can know the precise taskIds of launching tasks.
- // Find a change that has WINDOWING_MODE_MULTI_WINDOW.
if (
- taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW &&
+ taskInfo.windowingMode == windowingMode &&
(change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT)
) {
// Found one!
@@ -947,12 +1117,12 @@
animator.setDuration(QuickstepTransitionManager.SPLIT_LAUNCH_DURATION.toLong())
animator.addUpdateListener { valueAnimator: ValueAnimator ->
val progress =
- Interpolators.clampToProgress(
- Interpolators.LINEAR,
- valueAnimator.animatedFraction,
- 0.8f,
- 1f
- )
+ Interpolators.clampToProgress(
+ Interpolators.LINEAR,
+ valueAnimator.animatedFraction,
+ 0.8f,
+ 1f
+ )
for (leash in openingTargets) {
animTransaction.setAlpha(leash, progress)
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index 06edb14..8258ab8 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -38,36 +38,40 @@
import java.io.PrintWriter
/**
- * Holds/transforms/signs/seals/delivers information for the transient state of the user
- * selecting a first app to start split with and then choosing a second app.
- * This class DOES NOT associate itself with drag-and-drop split screen starts because they come
- * from the bad part of town.
+ * Holds/transforms/signs/seals/delivers information for the transient state of the user selecting a
+ * first app to start split with and then choosing a second app. This class DOES NOT associate
+ * itself with drag-and-drop split screen starts because they come from the bad part of town.
*
* After setting the correct fields for initial/second.* variables, this converts them into the
- * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary
- * data back via [getSplitLaunchData]. Note: there should be only one "initial" field and one
- * "second" field set, with the rest remaining null. (Exception: [Intent] and [UserHandle] are
- * always passed in together as a set, and are converted to a single [PendingIntent] or
+ * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary data
+ * back via [getSplitLaunchData]. Note: there should be only one "initial" field and one "second"
+ * field set, with the rest remaining null. (Exception: [Intent] and [UserHandle] are always passed
+ * in together as a set, and are converted to a single [PendingIntent] or
* [ShortcutInfo]+[PendingIntent] before launch.)
*
* [SplitLaunchType] indicates the type of tasks/apps/intents being launched given the provided
* state
*/
-class SplitSelectDataHolder(
- var context: Context?
-) {
+class SplitSelectDataHolder(var context: Context?) {
val TAG = SplitSelectDataHolder::class.simpleName
/**
- * Order of the constant indicates the order of which task/app was selected.
- * Ex. SPLIT_TASK_SHORTCUT means primary split app identified by task, secondary is shortcut
+ * Order of the constant indicates the order of which task/app was selected. Ex.
+ * SPLIT_TASK_SHORTCUT means primary split app identified by task, secondary is shortcut
* SPLIT_SHORTCUT_TASK means primary split app is determined by shortcut, secondary is task
*/
companion object {
- @IntDef(SPLIT_TASK_TASK, SPLIT_TASK_PENDINGINTENT, SPLIT_TASK_SHORTCUT,
- SPLIT_PENDINGINTENT_TASK, SPLIT_PENDINGINTENT_PENDINGINTENT, SPLIT_SHORTCUT_TASK,
- SPLIT_SINGLE_TASK_FULLSCREEN, SPLIT_SINGLE_INTENT_FULLSCREEN,
- SPLIT_SINGLE_SHORTCUT_FULLSCREEN)
+ @IntDef(
+ SPLIT_TASK_TASK,
+ SPLIT_TASK_PENDINGINTENT,
+ SPLIT_TASK_SHORTCUT,
+ SPLIT_PENDINGINTENT_TASK,
+ SPLIT_PENDINGINTENT_PENDINGINTENT,
+ SPLIT_SHORTCUT_TASK,
+ SPLIT_SINGLE_TASK_FULLSCREEN,
+ SPLIT_SINGLE_INTENT_FULLSCREEN,
+ SPLIT_SINGLE_SHORTCUT_FULLSCREEN
+ )
@Retention(AnnotationRetention.SOURCE)
annotation class SplitLaunchType
@@ -84,8 +88,7 @@
const val SPLIT_SINGLE_SHORTCUT_FULLSCREEN = 8
}
- @StagePosition
- private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED
+ @StagePosition private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED
private var itemInfo: ItemInfo? = null
private var secondItemInfo: ItemInfo? = null
private var splitEvent: EventEnum? = null
@@ -108,12 +111,16 @@
/**
* @param alreadyRunningTask if set to [android.app.ActivityTaskManager.INVALID_TASK_ID]
- * then @param intent will be used to launch the initial task
+ * then @param intent will be used to launch the initial task
* @param intent will be ignored if @param alreadyRunningTask is set
*/
- fun setInitialTaskSelect(intent: Intent?, @StagePosition stagePosition: Int,
- itemInfo: ItemInfo?, splitEvent: EventEnum?,
- alreadyRunningTask: Int) {
+ fun setInitialTaskSelect(
+ intent: Intent?,
+ @StagePosition stagePosition: Int,
+ itemInfo: ItemInfo?,
+ splitEvent: EventEnum?,
+ alreadyRunningTask: Int
+ ) {
if (alreadyRunningTask != INVALID_TASK_ID) {
initialTaskId = alreadyRunningTask
} else {
@@ -127,15 +134,21 @@
* To be called after first task selected from using a split shortcut from the fullscreen
* running app.
*/
- fun setInitialTaskSelect(info: RunningTaskInfo,
- @StagePosition stagePosition: Int, itemInfo: ItemInfo?,
- splitEvent: EventEnum?) {
+ fun setInitialTaskSelect(
+ info: RunningTaskInfo,
+ @StagePosition stagePosition: Int,
+ itemInfo: ItemInfo?,
+ splitEvent: EventEnum?
+ ) {
initialTaskId = info.taskId
setInitialData(stagePosition, splitEvent, itemInfo)
}
- private fun setInitialData(@StagePosition stagePosition: Int,
- event: EventEnum?, item: ItemInfo?) {
+ private fun setInitialData(
+ @StagePosition stagePosition: Int,
+ event: EventEnum?,
+ item: ItemInfo?
+ ) {
itemInfo = item
initialStagePosition = stagePosition
splitEvent = event
@@ -143,6 +156,7 @@
/**
* To be called as soon as user selects the second task (even if animations aren't complete)
+ *
* @param taskId The second task that will be launched.
*/
fun setSecondTask(taskId: Int, itemInfo: ItemInfo) {
@@ -152,6 +166,7 @@
/**
* To be called as soon as user selects the second app (even if animations aren't complete)
+ *
* @param intent The second intent that will be launched.
* @param user The user of that intent.
*/
@@ -162,8 +177,9 @@
}
/**
- * To be called as soon as user selects the second app (even if animations aren't complete)
- * Sets [secondUser] from that of the pendingIntent
+ * To be called as soon as user selects the second app (even if animations aren't complete) Sets
+ * [secondUser] from that of the pendingIntent
+ *
* @param pendingIntent The second PendingIntent that will be launched.
*/
fun setSecondTask(pendingIntent: PendingIntent, itemInfo: ItemInfo) {
@@ -173,9 +189,9 @@
}
/**
- * Similar to [setSecondTask] except this is to be called for widgets which can pass through
- * an extra intent from their RemoteResponse.
- * See [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
+ * Similar to [setSecondTask] except this is to be called for widgets which can pass through an
+ * extra intent from their RemoteResponse. See
+ * [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
*/
fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?, itemInfo: ItemInfo) {
setSecondTask(pendingIntent, itemInfo)
@@ -184,8 +200,7 @@
private fun getShortcutInfo(intent: Intent?, user: UserHandle?): ShortcutInfo? {
val intentPackage = intent?.getPackage() ?: return null
- val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)
- ?: return null
+ val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID) ?: return null
try {
val context: Context =
if (user != null) {
@@ -200,9 +215,7 @@
return null
}
- /**
- * Converts intents to pendingIntents, associating the [user] with the intent if provided
- */
+ /** Converts intents to pendingIntents, associating the [user] with the intent if provided */
private fun getPendingIntent(intent: Intent?, user: UserHandle?): PendingIntent? {
if (intent != initialIntent && intent != secondIntent) {
throw IllegalStateException("Invalid intent to convert to PendingIntent")
@@ -211,12 +224,21 @@
return if (intent == null) {
null
} else if (user != null) {
- PendingIntent.getActivityAsUser(context, 0, intent,
- PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT,
- null /* options */, user)
+ PendingIntent.getActivityAsUser(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT,
+ null /* options */,
+ user
+ )
} else {
- PendingIntent.getActivity(context, 0, intent,
- PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT)
+ PendingIntent.getActivity(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT
+ )
}
}
@@ -224,7 +246,7 @@
* @return [SplitLaunchData] with the necessary fields populated as determined by
* [SplitLaunchData.splitLaunchType]. This is to be used for launching splitscreen
*/
- fun getSplitLaunchData() : SplitLaunchData {
+ fun getSplitLaunchData(): SplitLaunchData {
// Convert all intents to shortcut infos to see if determine if we launch shortcut or intent
convertIntentsToFinalTypes()
val splitLaunchType = getSplitLaunchType()
@@ -241,7 +263,7 @@
* [SplitLaunchData.splitLaunchType]. This is to be used for launching an initially selected
* split task in fullscreen
*/
- fun getFullscreenLaunchData() : SplitLaunchData {
+ fun getFullscreenLaunchData(): SplitLaunchData {
// Convert all intents to shortcut infos to determine if we launch shortcut or intent
convertIntentsToFinalTypes()
val splitLaunchType = getFullscreenLaunchType()
@@ -249,21 +271,22 @@
return generateSplitLaunchData(splitLaunchType)
}
- private fun generateSplitLaunchData(@SplitLaunchType splitLaunchType: Int) : SplitLaunchData {
+ private fun generateSplitLaunchData(@SplitLaunchType splitLaunchType: Int): SplitLaunchData {
return SplitLaunchData(
- splitLaunchType,
- initialTaskId,
- secondTaskId,
- initialPendingIntent,
- secondPendingIntent,
- widgetSecondIntent,
- initialUser?.identifier ?: -1,
- secondUser?.identifier ?: -1,
- initialShortcut,
- secondShortcut,
- itemInfo,
- splitEvent,
- initialStagePosition)
+ splitLaunchType,
+ initialTaskId,
+ secondTaskId,
+ initialPendingIntent,
+ secondPendingIntent,
+ widgetSecondIntent,
+ initialUser?.identifier ?: -1,
+ secondUser?.identifier ?: -1,
+ initialShortcut,
+ secondShortcut,
+ itemInfo,
+ splitEvent,
+ initialStagePosition
+ )
}
/**
@@ -273,8 +296,7 @@
* Note that both [initialIntent] and [secondIntent] will be nullified on method return
*
* One caveat is that if [secondPendingIntent] is set, we will use that and *not* attempt to
- * convert [secondIntent].
- * This also leaves [widgetSecondIntent] untouched.
+ * convert [secondIntent]. This also leaves [widgetSecondIntent] untouched.
*/
private fun convertIntentsToFinalTypes() {
initialShortcut = getShortcutInfo(initialIntent, initialUser)
@@ -297,8 +319,8 @@
}
/**
- * Only valid data fields at this point should be tasks, shortcuts, or pendingIntents
- * Intents need to be converted in [convertIntentsToFinalTypes] prior to calling this method
+ * Only valid data fields at this point should be tasks, shortcuts, or pendingIntents Intents
+ * need to be converted in [convertIntentsToFinalTypes] prior to calling this method
*/
@VisibleForTesting
@SplitLaunchType
@@ -354,41 +376,40 @@
}
data class SplitLaunchData(
- @SplitLaunchType
- val splitLaunchType: Int,
- var initialTaskId: Int = INVALID_TASK_ID,
- var secondTaskId: Int = INVALID_TASK_ID,
- var initialPendingIntent: PendingIntent? = null,
- var secondPendingIntent: PendingIntent? = null,
- var widgetSecondIntent: Intent? = null,
- var initialUserId: Int = -1,
- var secondUserId: Int = -1,
- var initialShortcut: ShortcutInfo? = null,
- var secondShortcut: ShortcutInfo? = null,
- var itemInfo: ItemInfo? = null,
- var splitEvent: EventEnum? = null,
- val initialStagePosition: Int = STAGE_POSITION_UNDEFINED
+ @SplitLaunchType val splitLaunchType: Int,
+ var initialTaskId: Int = INVALID_TASK_ID,
+ var secondTaskId: Int = INVALID_TASK_ID,
+ var initialPendingIntent: PendingIntent? = null,
+ var secondPendingIntent: PendingIntent? = null,
+ var widgetSecondIntent: Intent? = null,
+ var initialUserId: Int = -1,
+ var secondUserId: Int = -1,
+ var initialShortcut: ShortcutInfo? = null,
+ var secondShortcut: ShortcutInfo? = null,
+ var itemInfo: ItemInfo? = null,
+ var splitEvent: EventEnum? = null,
+ val initialStagePosition: Int = STAGE_POSITION_UNDEFINED
)
/**
- * @return `true` if first task has been selected and waiting for the second task to be
- * chosen
+ * @return `true` if first task has been selected and waiting for the second task to be chosen
*/
fun isSplitSelectActive(): Boolean {
return isInitialTaskIntentSet() && !isSecondTaskIntentSet()
}
/**
- * @return `true` if the first and second task have been chosen and split is waiting to
- * be launched
+ * @return `true` if the first and second task have been chosen and split is waiting to be
+ * launched
*/
fun isBothSplitAppsConfirmed(): Boolean {
return isInitialTaskIntentSet() && isSecondTaskIntentSet()
}
private fun isInitialTaskIntentSet(): Boolean {
- return initialTaskId != INVALID_TASK_ID || initialIntent != null ||
- initialPendingIntent != null
+ return initialTaskId != INVALID_TASK_ID ||
+ initialIntent != null ||
+ initialPendingIntent != null
}
fun getInitialTaskId(): Int {
@@ -416,8 +437,9 @@
}
private fun isSecondTaskIntentSet(): Boolean {
- return secondTaskId != INVALID_TASK_ID || secondIntent != null
- || secondPendingIntent != null
+ return secondTaskId != INVALID_TASK_ID ||
+ secondIntent != null ||
+ secondPendingIntent != null
}
fun resetState() {
@@ -437,7 +459,7 @@
}
fun dump(prefix: String, writer: PrintWriter) {
- writer.println("$prefix ${javaClass.simpleName}")
+ writer.println("$prefix SplitSelectDataHolder")
writer.println("$prefix\tinitialStagePosition= $initialStagePosition")
writer.println("$prefix\tinitialTaskId= $initialTaskId")
writer.println("$prefix\tsecondTaskId= $secondTaskId")
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index c257be6..df1879e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -90,7 +90,6 @@
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
-import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SplitSelectionListener;
@@ -646,8 +645,13 @@
}
}
- public void initSplitFromDesktopController(QuickstepLauncher launcher) {
- initSplitFromDesktopController(new SplitFromDesktopController(launcher));
+ /**
+ * Init {@code SplitFromDesktopController}
+ */
+ public void initSplitFromDesktopController(QuickstepLauncher launcher,
+ OverviewComponentObserver overviewComponentObserver) {
+ initSplitFromDesktopController(
+ new SplitFromDesktopController(launcher, overviewComponentObserver));
}
@VisibleForTesting
@@ -956,12 +960,10 @@
private ISplitSelectListener mSplitSelectListener;
private Drawable mAppIcon;
- public SplitFromDesktopController(QuickstepLauncher launcher) {
+ public SplitFromDesktopController(QuickstepLauncher launcher,
+ OverviewComponentObserver overviewComponentObserver) {
mLauncher = launcher;
- RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(
- launcher.getApplicationContext());
- mOverviewComponentObserver =
- new OverviewComponentObserver(launcher.getApplicationContext(), deviceState);
+ mOverviewComponentObserver = overviewComponentObserver;
mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize(
R.dimen.split_placeholder_size);
mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize(
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index b6e6bf7..2396512 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -63,7 +63,7 @@
SplitSelectStateController controller) {
mLauncher = launcher;
mController = controller;
- mIconCache = LauncherAppState.getInstanceNoCreate().getIconCache();
+ mIconCache = LauncherAppState.getInstance(launcher).getIconCache();
mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize(
R.dimen.multi_window_task_divider_size) / 2;
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 555bf21..85d4f4b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -62,12 +62,13 @@
private final int mSplitPlaceholderInset;
public SplitWithKeyboardShortcutController(QuickstepLauncher launcher,
- SplitSelectStateController controller) {
+ SplitSelectStateController controller,
+ OverviewComponentObserver overviewComponentObserver,
+ RecentsAnimationDeviceState deviceState) {
mLauncher = launcher;
mController = controller;
- mDeviceState = new RecentsAnimationDeviceState(launcher.getApplicationContext());
- mOverviewComponentObserver = new OverviewComponentObserver(launcher.getApplicationContext(),
- mDeviceState);
+ mDeviceState = deviceState;
+ mOverviewComponentObserver = overviewComponentObserver;
mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize(
R.dimen.split_placeholder_size);
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index f823aff..99f10a7 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -46,7 +46,7 @@
* when swiping up (in gesture navigation mode).
*/
public class SwipePipToHomeAnimator extends RectFSpringAnim {
- private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName();
+ private static final String TAG = "SwipePipToHomeAnimator";
private static final float END_PROGRESS = 1.0f;
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 9268511..304b8f4 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -26,9 +26,11 @@
import android.view.WindowMetrics;
import com.android.internal.policy.SystemBarUtils;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
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;
@@ -49,6 +51,13 @@
}
@Override
+ public boolean isInDesktopMode() {
+ DesktopVisibilityController desktopController =
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ return desktopController != null && desktopController.areDesktopTasksVisible();
+ }
+
+ @Override
public int getRotation(Context displayInfoContext) {
return displayInfoContext.getResources().getConfiguration().windowConfiguration
.getRotation();
diff --git a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
index 21c9e09..69137cc 100644
--- a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
+++ b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
@@ -37,7 +37,7 @@
* @param <V> Type of object stored in the cache
*/
public class TaskKeyByLastActiveTimeCache<V> implements TaskKeyCache<V> {
- private static final String TAG = TaskKeyByLastActiveTimeCache.class.getSimpleName();
+ private static final String TAG = "TaskKeyByLastActiveTimeCache";
private final AtomicInteger mMaxSize;
private final Map<Integer, Entry<V>> mMap;
// To sort task id by last active time
diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
index 89d8cc4..e80d2a6 100644
--- a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
@@ -22,6 +22,8 @@
import static com.android.launcher3.BaseActivity.EVENT_RESUMED;
import static com.android.launcher3.BaseActivity.EVENT_STOPPED;
+import android.content.Context;
+
import androidx.annotation.NonNull;
import com.android.quickstep.RecentsModel;
@@ -45,6 +47,12 @@
private final Runnable mUnregisterCallback = this::unregister;
private final Runnable mResumeCallback = this::checkTaskLaunchFailed;
+ private final Context mContext;
+
+ public TaskRemovedDuringLaunchListener(Context context) {
+ mContext = context;
+ }
+
/**
* Registers a failure listener callback if it detects a scenario in which an app launch
* failed before the transition finished.
@@ -88,7 +96,7 @@
if (mLaunchedTaskId != INVALID_TASK_ID) {
final int launchedTaskId = mLaunchedTaskId;
final Runnable taskLaunchFailedCallback = mTaskLaunchFailedCallback;
- RecentsModel.INSTANCE.getNoCreate().isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
+ RecentsModel.INSTANCE.get(mContext).isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
if (taskRemoved) {
ActiveGestureLog.INSTANCE.addLog(
new ActiveGestureLog.CompoundString("Launch failed, task (id=")
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index fcb865f..9da4985 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -245,7 +245,7 @@
if (mSplitBounds == null) {
mStagePosition = STAGE_POSITION_UNDEFINED;
} else {
- mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds)
+ mStagePosition = runningTarget.taskId == splitInfo.leftTopTaskId
? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
mStagePosition);
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index b8afd9d..c3efc3c 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -34,7 +34,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
import com.android.launcher3.R;
-import com.android.launcher3.statemanager.StatefulActivity;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.BorderAnimator;
@@ -136,6 +135,10 @@
* Enable or disable showing border on focus change
*/
public void setBorderEnabled(boolean enabled) {
+ if (mBorderEnabled == enabled) {
+ return;
+ }
+
mBorderEnabled = enabled;
if (mFocusBorderAnimator != null) {
mFocusBorderAnimator.setBorderVisibility(/* visible= */
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
deleted file mode 100644
index 78b1763..0000000
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.views;
-
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RoundRectShape;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.desktop.DesktopRecentsTransitionController;
-import com.android.launcher3.icons.IconProvider;
-import com.android.launcher3.util.CancellableTask;
-import com.android.launcher3.util.RunnableList;
-import com.android.quickstep.RecentsModel;
-import com.android.quickstep.TaskThumbnailCache;
-import com.android.quickstep.util.RecentsOrientedState;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.QuickStepContract;
-
-import kotlin.Unit;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * TaskView that contains all tasks that are part of the desktop.
- */
-// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
-public class DesktopTaskView extends TaskView {
-
- private static final String TAG = DesktopTaskView.class.getSimpleName();
-
- private static final boolean DEBUG = false;
-
- @NonNull
- private List<Task> mTasks = new ArrayList<>();
-
- private final ArrayList<TaskThumbnailView> mSnapshotViews = new ArrayList<>();
-
- /** Maps {@code taskIds} to corresponding {@link TaskThumbnailView}s */
- private final SparseArray<TaskThumbnailView> mSnapshotViewMap = new SparseArray<>();
-
- private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
-
- private final TaskView.FullscreenDrawParams mSnapshotDrawParams;
-
- private View mBackgroundView;
-
- private int mChildCountAtInflation;
-
- public DesktopTaskView(Context context) {
- this(context, null);
- }
-
- public DesktopTaskView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DesktopTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- mSnapshotDrawParams = new FullscreenDrawParams(context) {
- @Override
- public float computeTaskCornerRadius(Context context) {
- return QuickStepContract.getWindowCornerRadius(context);
- }
-
- @Override
- public float computeWindowCornerRadius(Context context) {
- return QuickStepContract.getWindowCornerRadius(context);
- }
- };
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mBackgroundView = findViewById(R.id.background);
-
- int topMarginPx =
- mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
- FrameLayout.LayoutParams params = (LayoutParams) mBackgroundView.getLayoutParams();
- params.topMargin = topMarginPx;
- mBackgroundView.setLayoutParams(params);
-
- float[] outerRadii = new float[8];
- Arrays.fill(outerRadii, getTaskCornerRadius());
- RoundRectShape shape = new RoundRectShape(outerRadii, null, null);
- ShapeDrawable background = new ShapeDrawable(shape);
- background.setTint(getResources().getColor(android.R.color.system_neutral2_300,
- getContext().getTheme()));
- // TODO(b/244348395): this should be wallpaper
- mBackgroundView.setBackground(background);
-
- Drawable icon = getResources().getDrawable(R.drawable.ic_desktop, getContext().getTheme());
- Drawable iconBackground = getResources().getDrawable(R.drawable.bg_circle,
- getContext().getTheme());
- mIconView.setDrawable(new LayerDrawable(new Drawable[]{iconBackground, icon}));
-
- mChildCountAtInflation = getChildCount();
- }
-
- @Override
- protected Unit updateBorderBounds(@NonNull Rect bounds) {
- bounds.set(mBackgroundView.getLeft(), mBackgroundView.getTop(), mBackgroundView.getRight(),
- mBackgroundView.getBottom());
- return Unit.INSTANCE;
- }
-
- @Override
- public void bind(Task task, RecentsOrientedState orientedState) {
- bind(Collections.singletonList(task), orientedState);
- }
-
- /**
- * Updates this desktop task to the gives task list defined in {@code tasks}
- */
- public void bind(List<Task> tasks, RecentsOrientedState orientedState) {
- if (DEBUG) {
- StringBuilder sb = new StringBuilder();
- sb.append("bind tasks=").append(tasks.size()).append("\n");
- for (Task task : tasks) {
- sb.append(" key=").append(task.key).append("\n");
- }
- Log.d(TAG, sb.toString());
- }
- cancelPendingLoadTasks();
-
- mTasks = new ArrayList<>(tasks);
- mSnapshotViewMap.clear();
-
- // Ensure there are equal number of snapshot views and tasks.
- // More tasks than views, add views. More views than tasks, remove views.
- // TODO(b/251586230): use a ViewPool for creating TaskThumbnailViews
- if (mSnapshotViews.size() > mTasks.size()) {
- int diff = mSnapshotViews.size() - mTasks.size();
- for (int i = 0; i < diff; i++) {
- TaskThumbnailView snapshotView = mSnapshotViews.remove(0);
- removeView(snapshotView);
- }
- } else if (mSnapshotViews.size() < mTasks.size()) {
- int diff = mTasks.size() - mSnapshotViews.size();
- for (int i = 0; i < diff; i++) {
- TaskThumbnailView snapshotView = new TaskThumbnailView(getContext());
- mSnapshotViews.add(snapshotView);
- // Add snapshots from to position after the initial child views.
- addView(snapshotView, mChildCountAtInflation,
- new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- }
- }
-
- for (int i = 0; i < mTasks.size(); i++) {
- Task task = mTasks.get(i);
- TaskThumbnailView snapshotView = mSnapshotViews.get(i);
- snapshotView.bind(task);
- mSnapshotViewMap.put(task.key.id, snapshotView);
- }
-
- updateTaskIdContainer();
- updateTaskIdAttributeContainer();
-
- setOrientationState(orientedState);
- }
-
- private void updateTaskIdContainer() {
- // TODO(b/249371338): TaskView expects the array to have at least 2 elements.
- // At least 2 elements in the array
- mTaskIdContainer = new int[Math.max(mTasks.size(), 2)];
- for (int i = 0; i < mTasks.size(); i++) {
- mTaskIdContainer[i] = mTasks.get(i).key.id;
- }
- }
-
- private void updateTaskIdAttributeContainer() {
- // TODO(b/249371338): TaskView expects the array to have at least 2 elements.
- // At least 2 elements in the array
- mTaskIdAttributeContainer = new TaskIdAttributeContainer[Math.max(mTasks.size(), 2)];
- for (int i = 0; i < mTasks.size(); i++) {
- Task task = mTasks.get(i);
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
- mTaskIdAttributeContainer[i] = createAttributeContainer(task, thumbnailView);
- }
- }
-
- private TaskIdAttributeContainer createAttributeContainer(Task task,
- TaskThumbnailView thumbnailView) {
- return new TaskIdAttributeContainer(task, thumbnailView, createIconView(task),
- STAGE_POSITION_UNDEFINED);
- }
-
- private IconView createIconView(Task task) {
- IconView iconView = new IconView(mContext);
- PackageManager pm = mContext.getApplicationContext().getPackageManager();
- try {
- IconProvider provider = new IconProvider(mContext);
- Drawable appIcon = provider.getIcon(pm.getActivityInfo(task.topActivity,
- PackageManager.ComponentInfoFlags.of(0)));
- iconView.setDrawable(appIcon);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Package not found: " + task.topActivity.getPackageName(), e);
- }
- return iconView;
- }
-
- @Nullable
- @Override
- public Task getTask() {
- // TODO(b/249371338): returning first task. This won't work well with multiple tasks.
- return mTasks.size() > 0 ? mTasks.get(0) : null;
- }
-
- @Override
- public TaskThumbnailView getThumbnail() {
- // TODO(b/249371338): returning single thumbnail. This won't work well with multiple tasks.
- Task task = getTask();
- if (task != null) {
- return mSnapshotViewMap.get(task.key.id);
- }
- // Return the place holder snapshot views. Callers expect this to be non-null
- return mSnapshotView;
- }
-
- @Override
- public boolean containsTaskId(int taskId) {
- // Thumbnail map contains taskId -> thumbnail map. Use the keys for contains
- return mSnapshotViewMap.contains(taskId);
- }
-
- @Override
- public void onTaskListVisibilityChanged(boolean visible, int changes) {
- cancelPendingLoadTasks();
- if (visible) {
- RecentsModel model = RecentsModel.INSTANCE.get(getContext());
- TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
-
- if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- for (Task task : mTasks) {
- CancellableTask<?> thumbLoadRequest =
- thumbnailCache.updateThumbnailInBackground(task, thumbnailData -> {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
- if (thumbnailView != null) {
- thumbnailView.setThumbnail(task, thumbnailData);
- }
- });
- if (thumbLoadRequest != null) {
- mPendingThumbnailRequests.add(thumbLoadRequest);
- }
- }
- }
- } else {
- if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- for (Task task : mTasks) {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
- if (thumbnailView != null) {
- thumbnailView.setThumbnail(null, null);
- }
- // Reset the task thumbnail ref
- task.thumbnail = null;
- }
- }
- }
- }
-
- @Override
- protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
- DeviceProfile deviceProfile = mContainer.getDeviceProfile();
- int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
-
- LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
- snapshotParams.topMargin = thumbnailTopMargin;
-
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
- thumbnailView.setLayoutParams(snapshotParams);
- }
- }
-
- @Override
- protected void cancelPendingLoadTasks() {
- for (CancellableTask<?> cancellableTask : mPendingThumbnailRequests) {
- cancellableTask.cancel();
- }
- mPendingThumbnailRequests.clear();
- }
-
- @Override
- public boolean offerTouchToChildren(MotionEvent event) {
- return false;
- }
-
- @Override
- protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
- return false;
- }
-
- @Nullable
- @Override
- public RunnableList launchTaskAnimated() {
- RunnableList endCallback = new RunnableList();
-
- RecentsView recentsView = getRecentsView();
- DesktopRecentsTransitionController recentsController =
- recentsView.getDesktopRecentsController();
- if (recentsController != null) {
- recentsController.launchDesktopFromRecents(this, success -> {
- endCallback.executeAllAndDestroy();
- });
- }
-
- // Callbacks get run from recentsView for case when recents animation already running
- recentsView.addSideTaskLaunchCallback(endCallback);
- return endCallback;
- }
-
- @Override
- public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
- launchTasks();
- callback.accept(true);
- }
-
- @Override
- public boolean isDesktopTask() {
- return true;
- }
-
- @Override
- void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
- // Sets new thumbnails based on the incoming data and refreshes the rest.
- // Create a copy of the thumbnail map, so we can track thumbnails that need refreshing.
- SparseArray<TaskThumbnailView> thumbnailsToRefresh = mSnapshotViewMap.clone();
- if (thumbnailDatas != null) {
- for (Task task : mTasks) {
- int key = task.key.id;
- TaskThumbnailView thumbnailView = thumbnailsToRefresh.get(key);
- ThumbnailData thumbnailData = thumbnailDatas.get(key);
- if (thumbnailView != null && thumbnailData != null) {
- thumbnailView.setThumbnail(task, thumbnailData);
- // Remove this thumbnail from the list that should be refreshed.
- thumbnailsToRefresh.remove(key);
- }
- }
- }
-
- // Refresh the rest that were not updated.
- for (int i = 0; i < thumbnailsToRefresh.size(); i++) {
- thumbnailsToRefresh.valueAt(i).refresh();
- }
- }
-
- @Override
- public TaskThumbnailView[] getThumbnails() {
- TaskThumbnailView[] thumbnails = new TaskThumbnailView[mSnapshotViewMap.size()];
- for (int i = 0; i < thumbnails.length; i++) {
- thumbnails[i] = mSnapshotViewMap.valueAt(i);
- }
- return thumbnails;
- }
-
- @Override
- public void onRecycle() {
- resetPersistentViewTransforms();
- // Clear any references to the thumbnail (it will be re-read either from the cache or the
- // system on next bind)
- for (Task task : mTasks) {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
- if (thumbnailView != null) {
- thumbnailView.setThumbnail(task, null);
- }
- }
- setOverlayEnabled(false);
- onTaskListVisibilityChanged(false);
- setVisibility(VISIBLE);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int containerWidth = MeasureSpec.getSize(widthMeasureSpec);
- int containerHeight = MeasureSpec.getSize(heightMeasureSpec);
-
- setMeasuredDimension(containerWidth, containerHeight);
-
- int thumbnailTopMarginPx = mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
- containerHeight -= thumbnailTopMarginPx;
-
- int thumbnails = mSnapshotViewMap.size();
- if (thumbnails == 0) {
- return;
- }
-
- int windowWidth = mContainer.getDeviceProfile().widthPx;
- int windowHeight = mContainer.getDeviceProfile().heightPx;
-
- float scaleWidth = containerWidth / (float) windowWidth;
- float scaleHeight = containerHeight / (float) windowHeight;
-
- if (DEBUG) {
- Log.d(TAG,
- "onMeasure: container=[" + containerWidth + "," + containerHeight + "] window=["
- + windowWidth + "," + windowHeight + "] scale=[" + scaleWidth + ","
- + scaleHeight + "]");
- }
-
- // Desktop tile is a shrunk down version of launcher and freeform task thumbnails.
- for (int i = 0; i < mTasks.size(); i++) {
- Task task = mTasks.get(i);
- Rect taskSize = task.appBounds;
- if (taskSize == null) {
- // Default to quarter of the desktop if we did not get app bounds.
- taskSize = new Rect(0, 0, windowWidth / 4, windowHeight / 4);
- }
-
- int thumbWidth = (int) (taskSize.width() * scaleWidth);
- int thumbHeight = (int) (taskSize.height() * scaleHeight);
-
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
- if (thumbnailView != null) {
- thumbnailView.measure(MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY));
-
- // Position the task to the same position as it would be on the desktop
- Point positionInParent = task.positionInParent;
- if (positionInParent == null) {
- positionInParent = new Point(0, 0);
- }
- int taskX = (int) (positionInParent.x * scaleWidth);
- int taskY = (int) (positionInParent.y * scaleHeight);
- // move task down by margin size
- taskY += thumbnailTopMarginPx;
- thumbnailView.setX(taskX);
- thumbnailView.setY(taskY);
-
- if (DEBUG) {
- Log.d(TAG, "onMeasure: task=" + task.key + " thumb=[" + thumbWidth + ","
- + thumbHeight + "]" + " pos=[" + taskX + "," + taskY + "]");
- }
- }
- }
- }
-
- @Override
- public void setOverlayEnabled(boolean overlayEnabled) {
- // Intentional no-op to prevent setting smart actions overlay on thumbnails
- }
-
- @Override
- public void setFullscreenProgress(float progress) {
- // TODO(b/249371338): this copies parent implementation and makes it work for N thumbs
- progress = Utilities.boundToRange(progress, 0, 1);
- mFullscreenProgress = progress;
- if (mFullscreenProgress > 0) {
- // Don't show background while we are transitioning to/from fullscreen
- mBackgroundView.setVisibility(INVISIBLE);
- } else {
- mBackgroundView.setVisibility(VISIBLE);
- }
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
- thumbnailView.getTaskOverlay().setFullscreenProgress(progress);
- }
- updateSnapshotRadius();
- }
-
- @Override
- protected void updateSnapshotRadius() {
- super.updateSnapshotRadius();
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- if (i == 0) {
- // All snapshots share the same params. Only update it with the first snapshot.
- updateFullscreenParams(mSnapshotDrawParams);
- }
- mSnapshotViewMap.valueAt(i).setFullscreenParams(mSnapshotDrawParams);
- }
- }
-
- @Override
- protected void setIconsAndBannersTransitionProgress(float progress, boolean invert) {
- // no-op
- }
-
- @Override
- public void setColorTint(float amount, int tintColor) {
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- mSnapshotViewMap.valueAt(i).setDimAlpha(amount);
- }
- }
-
- @Override
- protected void applyThumbnailSplashAlpha() {
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- mSnapshotViewMap.valueAt(i).setSplashAlpha(mTaskThumbnailSplashAlpha);
- }
- }
-
- @Override
- void setThumbnailVisibility(int visibility, int taskId) {
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- mSnapshotViewMap.valueAt(i).setVisibility(visibility);
- }
- }
-
- @Override
- protected boolean confirmSecondSplitSelectApp() {
- // Desktop tile can't be in split screen
- return false;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
new file mode 100644
index 0000000..3565174
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views
+
+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.View
+import android.view.ViewGroup
+import androidx.core.view.updateLayoutParams
+import com.android.launcher3.LauncherState
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.CancellableTask
+import com.android.launcher3.util.RunnableList
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.ViewPool
+import com.android.quickstep.BaseContainerInterface
+import com.android.quickstep.RecentsModel
+import com.android.quickstep.util.RecentsOrientedState
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.system.QuickStepContract
+import java.util.function.Consumer
+
+/** TaskView that contains all tasks that are part of the desktop. */
+// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
+class DesktopTaskView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) :
+ TaskView(context, attrs) {
+
+ private val pendingThumbnailRequests = mutableListOf<CancellableTask<*>>()
+ private val snapshotDrawParams =
+ object : FullscreenDrawParams(context) {
+ override fun computeTaskCornerRadius(context: Context) =
+ QuickStepContract.getWindowCornerRadius(context)
+
+ override fun computeWindowCornerRadius(context: Context) =
+ QuickStepContract.getWindowCornerRadius(context)
+ }
+ private val taskThumbnailViewPool =
+ ViewPool<TaskThumbnailViewDeprecated>(
+ context,
+ this,
+ R.layout.task_thumbnail,
+ 10,
+ 0 // As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool.
+ )
+ private val tempPointF = PointF()
+ private val tempRect = Rect()
+ private lateinit var backgroundView: View
+ private var childCountAtInflation = 0
+
+ init {
+ mTaskContainers = ArrayList()
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+
+ backgroundView = findViewById(R.id.background)!!
+ val topMarginPx = mContainer.deviceProfile.overviewTaskThumbnailTopMarginPx
+ backgroundView.updateLayoutParams<LayoutParams> { topMargin = topMarginPx }
+
+ val outerRadii = FloatArray(8) { taskCornerRadius }
+ backgroundView.background =
+ ShapeDrawable(RoundRectShape(outerRadii, null, null)).apply {
+ setTint(resources.getColor(android.R.color.system_neutral2_300, context.theme))
+ }
+
+ val iconBackground = resources.getDrawable(R.drawable.bg_circle, context.theme)
+ val icon = resources.getDrawable(R.drawable.ic_desktop, context.theme)
+ setIcon(mIconView, LayerDrawable(arrayOf(iconBackground, icon)))
+
+ childCountAtInflation = childCount
+ }
+
+ override fun getThumbnailBounds(bounds: Rect, relativeToDragLayer: Boolean) {
+ if (relativeToDragLayer) {
+ mContainer.dragLayer.getDescendantRectRelativeToSelf(backgroundView, bounds)
+ } else {
+ bounds.set(
+ backgroundView.left,
+ backgroundView.top,
+ backgroundView.right,
+ backgroundView.bottom
+ )
+ }
+ }
+
+ override fun bind(task: Task, orientedState: RecentsOrientedState) {
+ bind(listOf(task), orientedState)
+ }
+
+ /** Updates this desktop task to the gives task list defined in `tasks` */
+ fun bind(tasks: List<Task>, orientedState: RecentsOrientedState) {
+ if (DEBUG) {
+ val sb = StringBuilder()
+ sb.append("bind tasks=").append(tasks.size).append("\n")
+ tasks.forEach { sb.append(" key=${it.key}\n") }
+ Log.d(TAG, sb.toString())
+ }
+ cancelPendingLoadTasks()
+
+ (mTaskContainers as ArrayList).ensureCapacity(tasks.size)
+ tasks.forEachIndexed { index, task ->
+ val thumbnailView: TaskThumbnailViewDeprecated
+ if (index >= mTaskContainers.size) {
+ thumbnailView = taskThumbnailViewPool.view
+ // Add thumbnailView from to position after the initial child views.
+ addView(
+ thumbnailView,
+ childCountAtInflation,
+ LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ )
+ } else {
+ thumbnailView = mTaskContainers[index].thumbnailView
+ }
+ thumbnailView.bind(task)
+ val taskContainer =
+ TaskContainer(
+ task,
+ thumbnailView,
+ mIconView,
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
+ )
+ if (index >= mTaskContainers.size) {
+ mTaskContainers.add(taskContainer)
+ } else {
+ mTaskContainers[index] = taskContainer
+ }
+ }
+ while (mTaskContainers.size > tasks.size) {
+ mTaskContainers.removeLast().apply {
+ removeView(thumbnailView)
+ taskThumbnailViewPool.recycle(thumbnailView)
+ }
+ }
+
+ setOrientationState(orientedState)
+ }
+
+ override fun onTaskListVisibilityChanged(visible: Boolean, changes: Int) {
+ cancelPendingLoadTasks()
+ if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
+ mTaskContainers.forEach {
+ if (visible) {
+ RecentsModel.INSTANCE.get(context)
+ .thumbnailCache
+ .updateThumbnailInBackground(it.task) { thumbnailData: ThumbnailData ->
+ it.thumbnailView.setThumbnail(it.task, thumbnailData)
+ }
+ ?.apply { pendingThumbnailRequests.add(this) }
+ } else {
+ it.thumbnailView.setThumbnail(null, null)
+ // Reset the task thumbnail ref
+ it.task.thumbnail = null
+ }
+ }
+ }
+ }
+
+ // thumbnailView is laid out differently and is handled in onMeasure
+ override fun setThumbnailOrientation(orientationState: RecentsOrientedState) {}
+
+ override fun cancelPendingLoadTasks() {
+ pendingThumbnailRequests.forEach { it.cancel() }
+ pendingThumbnailRequests.clear()
+ }
+
+ override fun launchTaskAnimated(): RunnableList? {
+ val recentsView = recentsView ?: return null
+ val endCallback = RunnableList()
+ val desktopController = recentsView.desktopRecentsController
+ if (desktopController != null) {
+ desktopController.launchDesktopFromRecents(this) { endCallback.executeAllAndDestroy() }
+ Log.d(
+ TAG,
+ "launchTaskAnimated - launchDesktopFromRecents: ${taskIds.contentToString()}"
+ )
+ } else {
+ Log.d(
+ TAG,
+ "launchTaskAnimated - recentsController is null: ${taskIds.contentToString()}"
+ )
+ }
+
+ // Callbacks get run from recentsView for case when recents animation already running
+ recentsView.addSideTaskLaunchCallback(endCallback)
+ return endCallback
+ }
+
+ override fun launchTask(callback: Consumer<Boolean>, isQuickswitch: Boolean) {
+ launchTasks()
+ callback.accept(true)
+ }
+
+ public override fun refreshThumbnails(thumbnailDatas: HashMap<Int, ThumbnailData?>?) {
+ // Sets new thumbnails based on the incoming data and refreshes the rest.
+ thumbnailDatas?.let {
+ mTaskContainers.forEach {
+ val thumbnailData = thumbnailDatas[it.task.key.id]
+ if (thumbnailData != null) {
+ it.thumbnailView.setThumbnail(it.task, thumbnailData)
+ } else {
+ // Refresh the rest that were not updated.
+ it.thumbnailView.refresh()
+ }
+ }
+ }
+ }
+
+ override fun onRecycle() {
+ resetPersistentViewTransforms()
+ // Clear any references to the thumbnail (it will be re-read either from the cache or the
+ // system on next bind)
+ mTaskContainers.forEach { it.thumbnailView.setThumbnail(it.task, null) }
+ setOverlayEnabled(false)
+ onTaskListVisibilityChanged(false)
+ visibility = VISIBLE
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ val containerWidth = MeasureSpec.getSize(widthMeasureSpec)
+ var containerHeight = MeasureSpec.getSize(heightMeasureSpec)
+ setMeasuredDimension(containerWidth, containerHeight)
+
+ if (mTaskContainers.isEmpty()) {
+ return
+ }
+
+ val thumbnailTopMarginPx = mContainer.deviceProfile.overviewTaskThumbnailTopMarginPx
+ containerHeight -= thumbnailTopMarginPx
+
+ BaseContainerInterface.getTaskDimension(mContext, mContainer.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] " +
+ "window=[$windowWidth,$windowHeight] scale=[$scaleWidth,$scaleHeight]"
+ )
+ }
+
+ // Desktop tile is a shrunk down version of launcher and freeform task thumbnails.
+ mTaskContainers.forEach {
+ // Default to quarter of the desktop if we did not get app bounds.
+ val taskSize =
+ it.task.appBounds
+ ?: tempRect.apply {
+ left = 0
+ top = 0
+ right = windowWidth / 4
+ bottom = windowHeight / 4
+ }
+ val thumbWidth = (taskSize.width() * scaleWidth).toInt()
+ val thumbHeight = (taskSize.height() * scaleHeight).toInt()
+ it.thumbnailView.measure(
+ MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY)
+ )
+
+ // 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.thumbnailView.x = taskX.toFloat()
+ it.thumbnailView.y = taskY.toFloat()
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onMeasure: task=${it.task.key} thumb=[$thumbWidth,$thumbHeight]" +
+ " pos=[$taskX,$taskY]"
+ )
+ }
+ }
+ }
+
+ // TODO(b/330685808) support overlay for Screenshot action
+ override fun setOverlayEnabled(overlayEnabled: Boolean) {}
+
+ override fun setFullscreenProgress(progress: Float) {
+ // TODO(b/249371338): this copies parent implementation and makes it work for N thumbs
+ val boundProgress = Utilities.boundToRange(progress, 0f, 1f)
+ mFullscreenProgress = boundProgress
+ mIconView.setVisibility(if (boundProgress < 1) VISIBLE else INVISIBLE)
+ // Don't show background while we are transitioning to/from fullscreen
+ backgroundView.visibility = if (mFullscreenProgress > 0) INVISIBLE else VISIBLE
+ mTaskContainers.forEach {
+ it.thumbnailView.taskOverlay.setFullscreenProgress(boundProgress)
+ }
+ // Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
+ // oversized and banner would look disproportionately large.
+ if (
+ mContainer.getOverviewPanel<RecentsView<*, *>>().getStateManager().state !=
+ LauncherState.BACKGROUND_APP
+ ) {
+ setIconsAndBannersTransitionProgress(boundProgress, true)
+ }
+ updateSnapshotRadius()
+ }
+
+ override fun updateSnapshotRadius() {
+ super.updateSnapshotRadius()
+ updateFullscreenParams(snapshotDrawParams)
+ mTaskContainers.forEach { it.thumbnailView.setFullscreenParams(snapshotDrawParams) }
+ }
+
+ override fun setColorTint(amount: Float, tintColor: Int) {
+ mTaskContainers.forEach { it.thumbnailView.dimAlpha = amount }
+ }
+
+ override fun applyThumbnailSplashAlpha() {
+ mTaskContainers.forEach { it.thumbnailView.setSplashAlpha(mTaskThumbnailSplashAlpha) }
+ }
+
+ public override fun setThumbnailVisibility(visibility: Int, taskId: Int) {
+ mTaskContainers.forEach { it.thumbnailView.visibility = visibility }
+ }
+
+ // Desktop tile can't be in split screen
+ override fun confirmSecondSplitSelectApp(): Boolean = false
+
+ companion object {
+ private const val TAG = "DesktopTaskView"
+ private const val DEBUG = true
+ 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
index 8fa5375..4df9414 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -19,7 +19,7 @@
import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
import static com.android.launcher3.Utilities.prefixTextWithIcon;
-import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
+import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
@@ -79,7 +79,7 @@
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.class.getSimpleName();
+ private static final String TAG = "DigitalWellBeingToast";
private final RecentsViewContainer mContainer;
private final TaskView mTaskView;
@@ -140,7 +140,7 @@
public void initialize(Task task) {
mAppUsageLimitTimeMs = mAppRemainingTimeMs = -1;
mTask = task;
- THREAD_POOL_EXECUTOR.execute(() -> {
+ ORDERED_BG_EXECUTOR.execute(() -> {
AppUsageLimit usageLimit = null;
try {
usageLimit = mLauncherApps.getAppUsageLimit(
@@ -320,12 +320,12 @@
(FrameLayout.LayoutParams) mBanner.getLayoutParams();
DeviceProfile deviceProfile = mContainer.getDeviceProfile();
layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
- mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
+ mTaskView.getFirstThumbnailView().getLayoutParams()).bottomMargin;
RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
Pair<Float, Float> translations = orientationHandler
.getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
- mTaskView.getThumbnails(), mTask.key.id, mBanner);
+ mTaskView.getThumbnailViews(), mTask.key.id, mBanner);
mSplitOffsetTranslationX = translations.first;
mSplitOffsetTranslationY = translations.second;
updateTranslationY();
diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
index 0d49309..e024995 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
+++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
@@ -36,17 +36,18 @@
* animation. Consists of a rectangular background that splits into two, and two app icons that
* increase in size during the animation.
*/
-class FloatingAppPairBackground(
- context: Context,
- private val floatingView: FloatingAppPairView, // the view that we will draw this background on
- private val appIcon1: Drawable,
- private val appIcon2: Drawable,
- dividerPos: Int
+open class FloatingAppPairBackground(
+ context: Context,
+ // the view that we will draw this background on
+ protected val floatingView: FloatingAppPairView,
+ private val appIcon1: Drawable,
+ private val appIcon2: Drawable?,
+ dividerPos: Int
) : Drawable() {
companion object {
// Design specs -- app icons start small and expand during the animation
- private val STARTING_ICON_SIZE_PX = Utilities.dpToPx(22f)
- private val ENDING_ICON_SIZE_PX = Utilities.dpToPx(66f)
+ internal val STARTING_ICON_SIZE_PX = Utilities.dpToPx(22f)
+ internal val ENDING_ICON_SIZE_PX = Utilities.dpToPx(66f)
// Null values to use with drawDoubleRoundRect(), since there doesn't seem to be any other
// API for drawing rectangles with 4 different corner radii.
@@ -58,13 +59,13 @@
private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
// Animation interpolators
- private val expandXInterpolator: Interpolator
- private val expandYInterpolator: Interpolator
+ protected val expandXInterpolator: Interpolator
+ protected val expandYInterpolator: Interpolator
private val cellSplitInterpolator: Interpolator
- private val iconFadeInterpolator: Interpolator
+ protected val iconFadeInterpolator: Interpolator
// Device-specific measurements
- private val deviceCornerRadius: Float
+ protected val deviceCornerRadius: Float
private val deviceHalfDividerSize: Float
private val desiredSplitRatio: Float
@@ -214,7 +215,7 @@
canvas.save()
canvas.translate(changingIcon2Left, changingIconTop)
canvas.scale(changingIconScaleX, changingIconScaleY)
- appIcon2.alpha = changingIconAlpha
+ appIcon2!!.alpha = changingIconAlpha
appIcon2.draw(canvas)
canvas.restore()
}
@@ -312,7 +313,7 @@
canvas.save()
canvas.translate(changingIconLeft, changingIcon2Top)
canvas.scale(changingIconScaleX, changingIconScaleY)
- appIcon2.alpha = changingIconAlpha
+ appIcon2!!.alpha = changingIconAlpha
appIcon2.draw(canvas)
canvas.restore()
}
@@ -325,7 +326,7 @@
* @param radii An array of 8 radii for the corners: top left x, top left y, top right x, top
* right y, bottom right x, and so on.
*/
- private fun drawCustomRoundedRect(c: Canvas, rect: RectF, radii: FloatArray) {
+ protected fun drawCustomRoundedRect(c: Canvas, rect: RectF, radii: FloatArray) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Canvas.drawDoubleRoundRect is supported from Q onward
c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, backgroundPaint)
diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
index e90aa13..e8d1cc1 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
+++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
@@ -40,8 +40,8 @@
fun getFloatingAppPairView(
launcher: StatefulActivity<*>,
originalView: View,
- appIcon1: Drawable,
- appIcon2: Drawable,
+ appIcon1: Drawable?,
+ appIcon2: Drawable?,
dividerPos: Int
): FloatingAppPairView {
val dragLayer: ViewGroup = launcher.getDragLayer()
@@ -64,8 +64,8 @@
fun init(
launcher: StatefulActivity<*>,
originalView: View,
- appIcon1: Drawable,
- appIcon2: Drawable,
+ appIcon1: Drawable?,
+ appIcon2: Drawable?,
dividerPos: Int
) {
val viewBounds = Rect(0, 0, originalView.width, originalView.height)
@@ -92,7 +92,14 @@
layoutParams = lp
// Prepare to draw app pair icon background
- background = FloatingAppPairBackground(context, this, appIcon1, appIcon2, dividerPos)
+ background = if (appIcon1 == null || appIcon2 == null) {
+ val iconToAnimate = appIcon1 ?: appIcon2
+ checkNotNull(iconToAnimate)
+ FloatingFullscreenAppPairBackground(context, this, iconToAnimate,
+ dividerPos)
+ } else {
+ FloatingAppPairBackground(context, this, appIcon1, appIcon2, dividerPos)
+ }
background.setBounds(0, 0, lp.width, lp.height)
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingFullscreenAppPairBackground.kt b/quickstep/src/com/android/quickstep/views/FloatingFullscreenAppPairBackground.kt
new file mode 100644
index 0000000..8cd997f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingFullscreenAppPairBackground.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.content.Context
+import android.graphics.Canvas
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+
+class FloatingFullscreenAppPairBackground(
+ context: Context,
+ floatingView: FloatingAppPairView,
+ private val iconToLaunch: Drawable,
+ dividerPos: Int) :
+ FloatingAppPairBackground(
+ context,
+ floatingView,
+ iconToLaunch,
+ null /*appIcon2*/,
+ dividerPos
+) {
+
+ /** Animates the background as if launching a fullscreen task. */
+ override fun draw(canvas: Canvas) {
+ val progress = floatingView.progress
+
+ // Since the entire floating app pair surface is scaling up during this animation, we
+ // scale down most of these drawn elements so that they appear the proper size on-screen.
+ val scaleFactorX = floatingView.scaleX
+ val scaleFactorY = floatingView.scaleY
+
+ // Get the bounds where we will draw the background image
+ val width = bounds.width().toFloat()
+ val height = bounds.height().toFloat()
+
+ // Get device-specific measurements
+ val cornerRadiusX = deviceCornerRadius / scaleFactorX
+ val cornerRadiusY = deviceCornerRadius / scaleFactorY
+
+ // Draw background
+ drawCustomRoundedRect(
+ canvas,
+ RectF(0f, 0f, width, height),
+ floatArrayOf(
+ cornerRadiusX,
+ cornerRadiusY,
+ cornerRadiusX,
+ cornerRadiusY,
+ cornerRadiusX,
+ cornerRadiusY,
+ cornerRadiusX,
+ cornerRadiusY,
+ )
+ )
+
+ // Calculate changing measurements for icon.
+ val changingIconSizeX =
+ (STARTING_ICON_SIZE_PX +
+ ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+ expandXInterpolator.getInterpolation(progress))) / scaleFactorX
+ val changingIconSizeY =
+ (STARTING_ICON_SIZE_PX +
+ ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+ expandYInterpolator.getInterpolation(progress))) / scaleFactorY
+
+ val changingIcon1Left = (width / 2f) - (changingIconSizeX / 2f)
+ val changingIconTop = (height / 2f) - (changingIconSizeY / 2f)
+ val changingIconScaleX = changingIconSizeX / iconToLaunch.bounds.width()
+ val changingIconScaleY = changingIconSizeY / iconToLaunch.bounds.height()
+ val changingIconAlpha =
+ (255 - (255 * iconFadeInterpolator.getInterpolation(progress))).toInt()
+
+ // Draw icon
+ canvas.save()
+ canvas.translate(changingIcon1Left, changingIconTop)
+ canvas.scale(changingIconScaleX, changingIconScaleY)
+ iconToLaunch.alpha = changingIconAlpha
+ iconToLaunch.draw(canvas)
+ canvas.restore()
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
index d869fed..e5a7333 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
@@ -31,7 +31,7 @@
/**
* A child view of {@link com.android.quickstep.views.FloatingTaskView} to draw the thumbnail in a
* rounded corner frame. While the purpose of this class sounds similar to
- * {@link TaskThumbnailView}, it doesn't need a lot of complex logic in {@link TaskThumbnailView}
+ * {@link TaskThumbnailViewDeprecated}, it doesn't need a lot of complex logic in {@link TaskThumbnailViewDeprecated}
* in relation to moving with {@link RecentsView}.
*/
public class FloatingTaskThumbnailView extends View {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
deleted file mode 100644
index 9e1c856..0000000
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ /dev/null
@@ -1,525 +0,0 @@
-package com.android.quickstep.views;
-
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-
-import static com.android.launcher3.Flags.enableOverviewIconMenu;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStub;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.jank.Cuj;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.CancellableTask;
-import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.TransformingTouchDelegate;
-import com.android.quickstep.RecentsModel;
-import com.android.quickstep.TaskIconCache;
-import com.android.quickstep.TaskThumbnailCache;
-import com.android.quickstep.util.RecentsOrientedState;
-import com.android.quickstep.util.SplitSelectStateController;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
-import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
-
-import kotlin.Unit;
-
-import java.util.HashMap;
-import java.util.function.Consumer;
-
-/**
- * TaskView that contains and shows thumbnails for not one, BUT TWO(!!) tasks
- *
- * That's right. If you call within the next 5 minutes we'll go ahead and double your order and
- * send you !! TWO !! Tasks along with their TaskThumbnailViews complimentary. On. The. House.
- * And not only that, we'll even clean up your thumbnail request if you don't like it.
- * All the benefits of one TaskView, except DOUBLED!
- *
- * (Icon loading sold separately, fees may apply. Shipping & Handling for Overlays not included).
- */
-public class GroupedTaskView extends TaskView {
-
- @Nullable
- private Task mSecondaryTask;
- private TaskThumbnailView mSnapshotView2;
- private TaskViewIcon mIconView2;
- @Nullable
- private CancellableTask<ThumbnailData> mThumbnailLoadRequest2;
- @Nullable
- private CancellableTask mIconLoadRequest2;
- private final float[] mIcon2CenterCoords = new float[2];
- private TransformingTouchDelegate mIcon2TouchDelegate;
- @Nullable private SplitBounds mSplitBoundsConfig;
- private final DigitalWellBeingToast mDigitalWellBeingToast2;
-
- public GroupedTaskView(Context context) {
- this(context, null);
- }
-
- public GroupedTaskView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public GroupedTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mDigitalWellBeingToast2 = new DigitalWellBeingToast(mContainer, this);
- }
-
- @Override
- protected Unit updateBorderBounds(@NonNull Rect bounds) {
- if (mSplitBoundsConfig == null) {
- super.updateBorderBounds(bounds);
- return Unit.INSTANCE;
- }
- bounds.set(
- Math.min(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
- mSnapshotView2.getLeft() + Math.round(mSnapshotView2.getTranslationX())),
- Math.min(mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
- mSnapshotView2.getTop() + Math.round(mSnapshotView2.getTranslationY())),
- Math.max(mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
- mSnapshotView2.getRight() + Math.round(mSnapshotView2.getTranslationX())),
- Math.max(mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()),
- mSnapshotView2.getBottom() + Math.round(mSnapshotView2.getTranslationY())));
- return Unit.INSTANCE;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mSnapshotView2 = findViewById(R.id.bottomright_snapshot);
- ViewStub iconViewStub2 = findViewById(R.id.bottomRight_icon);
- if (enableOverviewIconMenu()) {
- iconViewStub2.setLayoutResource(R.layout.icon_app_chip_view);
- } else {
- iconViewStub2.setLayoutResource(R.layout.icon_view);
- }
- mIconView2 = (TaskViewIcon) iconViewStub2.inflate();
- mIcon2TouchDelegate = new TransformingTouchDelegate(mIconView2.asView());
- }
-
- public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
- @Nullable SplitBounds splitBoundsConfig) {
- super.bind(primary, orientedState);
- mSecondaryTask = secondary;
- mTaskIdContainer[1] = secondary.key.id;
- mTaskIdAttributeContainer[1] = new TaskIdAttributeContainer(secondary, mSnapshotView2,
- mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT);
- mTaskIdAttributeContainer[0].setStagePosition(
- SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
- mSnapshotView2.bind(secondary);
- mSplitBoundsConfig = splitBoundsConfig;
- if (mSplitBoundsConfig == null) {
- return;
- }
- mSnapshotView.getPreviewPositionHelper().setSplitBounds(
- convertLauncherSplitBoundsToShell(splitBoundsConfig),
- PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT);
- mSnapshotView2.getPreviewPositionHelper().setSplitBounds(
- convertLauncherSplitBoundsToShell(splitBoundsConfig),
- PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT);
- }
-
- /**
- * Sets up an on-click listener and the visibility for show_windows icon on top of each task.
- */
- @Override
- public void setUpShowAllInstancesListener() {
- // sets up the listener for the left/top task
- super.setUpShowAllInstancesListener();
-
- // right/bottom task's base package name
- String taskPackageName = mTaskIdAttributeContainer[1].getTask().key.getPackageName();
-
- // icon of the right/bottom task
- View showWindowsView = findViewById(R.id.show_windows_right);
- updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName));
- }
-
- @Override
- public void onTaskListVisibilityChanged(boolean visible, int changes) {
- super.onTaskListVisibilityChanged(visible, changes);
- if (visible) {
- RecentsModel model = RecentsModel.INSTANCE.get(getContext());
- TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
- TaskIconCache iconCache = model.getIconCache();
-
- if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- mThumbnailLoadRequest2 = thumbnailCache.updateThumbnailInBackground(mSecondaryTask,
- thumbnailData -> mSnapshotView2.setThumbnail(
- mSecondaryTask, thumbnailData
- ));
- }
-
- if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
- mIconLoadRequest2 = iconCache.updateIconInBackground(mSecondaryTask,
- (task) -> {
- setIcon(mIconView2, task.icon);
- if (enableOverviewIconMenu()) {
- setText(mIconView2, task.title);
- }
- mDigitalWellBeingToast2.initialize(mSecondaryTask);
- mDigitalWellBeingToast2.setSplitConfiguration(mSplitBoundsConfig);
- mDigitalWellBeingToast.setSplitConfiguration(mSplitBoundsConfig);
- });
- }
- } else {
- if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- mSnapshotView2.setThumbnail(null, null);
- // Reset the task thumbnail reference as well (it will be fetched from the cache or
- // reloaded next time we need it)
- mSecondaryTask.thumbnail = null;
- }
- if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
- setIcon(mIconView2, null);
- if (enableOverviewIconMenu()) {
- setText(mIconView2, null);
- }
- }
- }
- }
-
- public void updateSplitBoundsConfig(SplitBounds splitBounds) {
- mSplitBoundsConfig = splitBounds;
- invalidate();
- }
-
- @Nullable
- public SplitBounds getSplitBoundsConfig() {
- return mSplitBoundsConfig;
- }
-
- /**
- * Returns the {@link PersistentSnapPosition} of this pair of tasks.
- */
- public @PersistentSnapPosition int getSnapPosition() {
- if (mSplitBoundsConfig == null) {
- throw new IllegalStateException("mSplitBoundsConfig is null");
- }
-
- return mSplitBoundsConfig.snapPosition;
- }
-
- @Override
- public boolean offerTouchToChildren(MotionEvent event) {
- computeAndSetIconTouchDelegate(mIconView2, mIcon2CenterCoords, mIcon2TouchDelegate);
- if (mIcon2TouchDelegate.onTouchEvent(event)) {
- return true;
- }
-
- return super.offerTouchToChildren(event);
- }
-
- @Override
- protected void cancelPendingLoadTasks() {
- super.cancelPendingLoadTasks();
- if (mThumbnailLoadRequest2 != null) {
- mThumbnailLoadRequest2.cancel();
- mThumbnailLoadRequest2 = null;
- }
- if (mIconLoadRequest2 != null) {
- mIconLoadRequest2.cancel();
- mIconLoadRequest2 = null;
- }
- }
-
- @Nullable
- @Override
- public RunnableList launchTaskAnimated() {
- if (mTask == null || mSecondaryTask == null) {
- return null;
- }
-
- RunnableList endCallback = new RunnableList();
- RecentsView recentsView = getRecentsView();
- // Callbacks run from remote animation when recents animation not currently running
- InteractionJankMonitorWrapper.begin(this, Cuj.CUJ_SPLIT_SCREEN_ENTER,
- "Enter form GroupedTaskView");
- launchTaskInternal(success -> {
- endCallback.executeAllAndDestroy();
- InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
- }, false /* freezeTaskList */, true /*launchingExistingTaskview*/);
-
-
- // Callbacks get run from recentsView for case when recents animation already running
- recentsView.addSideTaskLaunchCallback(endCallback);
- return endCallback;
- }
-
- @Override
- public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
- launchTaskInternal(callback, isQuickswitch, false /*launchingExistingTaskview*/);
- }
-
- /**
- * @param launchingExistingTaskView {@link SplitSelectStateController#launchExistingSplitPair}
- * uses existence of GroupedTaskView as control flow of how to animate in the incoming task. If
- * we're launching from overview (from overview thumbnails) then pass in {@code true},
- * otherwise pass in {@code false} for case like quickswitching from home to task
- */
- private void launchTaskInternal(@NonNull Consumer<Boolean> callback, boolean isQuickswitch,
- boolean launchingExistingTaskView) {
- getRecentsView().getSplitSelectController().launchExistingSplitPair(
- launchingExistingTaskView ? this : null, mTask.key.id,
- mSecondaryTask.key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
- callback, isQuickswitch, getSnapPosition());
- }
-
- @Override
- void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
- super.refreshThumbnails(thumbnailDatas);
- if (mSecondaryTask != null && thumbnailDatas != null) {
- final ThumbnailData thumbnailData = thumbnailDatas.get(mSecondaryTask.key.id);
- if (thumbnailData != null) {
- mSnapshotView2.setThumbnail(mSecondaryTask, thumbnailData);
- return;
- }
- }
-
- mSnapshotView2.refresh();
- }
-
- @Override
- public boolean containsTaskId(int taskId) {
- return (mTask != null && mTask.key.id == taskId)
- || (mSecondaryTask != null && mSecondaryTask.key.id == taskId);
- }
-
- @Override
- public TaskThumbnailView[] getThumbnails() {
- return new TaskThumbnailView[]{mSnapshotView, mSnapshotView2};
- }
-
- @Override
- protected int getLastSelectedChildTaskIndex() {
- SplitSelectStateController splitSelectController =
- getRecentsView().getSplitSelectController();
- if (splitSelectController.isDismissingFromSplitPair()) {
- // return the container index of the task that wasn't initially selected to split with
- // because that is the only remaining app that can be selected. The coordinate checks
- // below aren't reliable since both of those views may be gone/transformed
- int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
- if (initSplitTaskId != INVALID_TASK_ID) {
- return initSplitTaskId == mTask.key.id ? 1 : 0;
- }
- }
-
- // Check which of the two apps was selected
- if (isCoordInView(mIconView2.asView(), mLastTouchDownPosition)
- || isCoordInView(mSnapshotView2, mLastTouchDownPosition)) {
- return 1;
- }
- return super.getLastSelectedChildTaskIndex();
- }
-
- private boolean isCoordInView(View v, PointF position) {
- float[] localPos = new float[]{position.x, position.y};
- Utilities.mapCoordInSelfToDescendant(v, this, localPos);
- return Utilities.pointInView(v, localPos[0], localPos[1], 0f /* slop */);
- }
-
- @Override
- public void onRecycle() {
- super.onRecycle();
- mSnapshotView2.setThumbnail(mSecondaryTask, null);
- mSplitBoundsConfig = null;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- setMeasuredDimension(widthSize, heightSize);
- if (mSplitBoundsConfig == null || mSnapshotView == null || mSnapshotView2 == null) {
- return;
- }
- int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
- if (initSplitTaskId == INVALID_TASK_ID) {
- getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
- mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig,
- mContainer.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL);
- // Should we be having a separate translation step apart from the measuring above?
- // The following only applies to large screen for now, but for future reference
- // we'd want to abstract this out in PagedViewHandlers to get the primary/secondary
- // translation directions
- mSnapshotView.applySplitSelectTranslateX(mSnapshotView.getTranslationX());
- mSnapshotView.applySplitSelectTranslateY(mSnapshotView.getTranslationY());
- mSnapshotView2.applySplitSelectTranslateX(mSnapshotView2.getTranslationX());
- mSnapshotView2.applySplitSelectTranslateY(mSnapshotView2.getTranslationY());
- } else {
- // Currently being split with this taskView, let the non-split selected thumbnail
- // take up full thumbnail area
- TaskIdAttributeContainer container =
- mTaskIdAttributeContainer[initSplitTaskId == mTask.key.id ? 1 : 0];
- container.getThumbnailView().measure(widthMeasureSpec,
- View.MeasureSpec.makeMeasureSpec(
- heightSize -
- mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx,
- MeasureSpec.EXACTLY));
- }
- if (!enableOverviewIconMenu()) {
- updateIconPlacement();
- }
- }
-
- @Override
- public void setOverlayEnabled(boolean overlayEnabled) {
- if (FeatureFlags.enableAppPairs()) {
- super.setOverlayEnabled(overlayEnabled);
- } else {
- // Intentional no-op to prevent setting smart actions overlay on thumbnails
- }
- }
-
- @Override
- public void setOrientationState(RecentsOrientedState orientationState) {
- DeviceProfile deviceProfile = mContainer.getDeviceProfile();
- if (enableOverviewIconMenu() && mSplitBoundsConfig != null) {
- ViewGroup.LayoutParams layoutParams = getLayoutParams();
- Pair<Point, Point> groupedTaskViewSizes =
- orientationState.getOrientationHandler().getGroupedTaskViewSizes(
- deviceProfile,
- mSplitBoundsConfig,
- layoutParams.width,
- layoutParams.height
- );
- int iconViewMarginStart = getResources().getDimensionPixelSize(
- R.dimen.task_thumbnail_icon_menu_expanded_top_start_margin);
- int iconViewBackgroundMarginStart = getResources().getDimensionPixelSize(
- R.dimen.task_thumbnail_icon_menu_background_margin_top_start);
- int iconMargins = (iconViewMarginStart + iconViewBackgroundMarginStart) * 2;
- ((IconAppChipView) mIconView).setMaxWidth(groupedTaskViewSizes.first.x - iconMargins);
- ((IconAppChipView) mIconView2).setMaxWidth(groupedTaskViewSizes.second.x - iconMargins);
- }
- // setMaxWidth() needs to be called before mIconView.setIconOrientation which is called in
- // the super below.
- super.setOrientationState(orientationState);
-
- boolean isGridTask = deviceProfile.isTablet && !isFocusedTask();
- mIconView2.setIconOrientation(orientationState, isGridTask);
- updateIconPlacement();
- updateSecondaryDwbPlacement();
- }
-
- private void updateIconPlacement() {
- if (mSplitBoundsConfig == null) {
- return;
- }
-
- DeviceProfile deviceProfile = mContainer.getDeviceProfile();
- int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
- boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-
- if (enableOverviewIconMenu()) {
- ViewGroup.LayoutParams layoutParams = getLayoutParams();
- Pair<Point, Point> groupedTaskViewSizes =
- getPagedOrientationHandler()
- .getGroupedTaskViewSizes(
- deviceProfile,
- mSplitBoundsConfig,
- layoutParams.width,
- layoutParams.height
- );
-
- getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
- taskIconHeight, groupedTaskViewSizes.first.x, groupedTaskViewSizes.first.y,
- getLayoutParams().height, getLayoutParams().width, isRtl, deviceProfile,
- mSplitBoundsConfig);
- } else {
- getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
- taskIconHeight, mSnapshotView.getMeasuredWidth(),
- mSnapshotView.getMeasuredHeight(), getMeasuredHeight(), getMeasuredWidth(),
- isRtl, deviceProfile, mSplitBoundsConfig);
- }
- }
-
- private void updateSecondaryDwbPlacement() {
- if (mSecondaryTask == null) {
- return;
- }
- mDigitalWellBeingToast2.initialize(mSecondaryTask);
- }
-
- @Override
- protected void updateSnapshotRadius() {
- super.updateSnapshotRadius();
- mSnapshotView2.setFullscreenParams(mCurrentFullscreenParams);
- }
-
- @Override
- protected void setIconsAndBannersTransitionProgress(float progress, boolean invert) {
- super.setIconsAndBannersTransitionProgress(progress, invert);
- // Value set by super call
- float scale = mIconView.getAlpha();
- mIconView2.setContentAlpha(scale);
- mDigitalWellBeingToast2.updateBannerOffset(1f - scale);
- }
-
- @Override
- public void setColorTint(float amount, int tintColor) {
- super.setColorTint(amount, tintColor);
- mIconView2.setIconColorTint(tintColor, amount);
- mSnapshotView2.setDimAlpha(amount);
- mDigitalWellBeingToast2.setBannerColorTint(tintColor, amount);
- }
-
- @Override
- protected void applyThumbnailSplashAlpha() {
- super.applyThumbnailSplashAlpha();
- mSnapshotView2.setSplashAlpha(mTaskThumbnailSplashAlpha);
- }
-
- @Override
- protected void refreshTaskThumbnailSplash() {
- super.refreshTaskThumbnailSplash();
- mSnapshotView2.refreshSplashView();
- }
-
- @Override
- protected void resetViewTransforms() {
- super.resetViewTransforms();
- mSnapshotView2.resetViewTransforms();
- }
-
- /**
- * Sets visibility for thumbnails and associated elements (DWB banners).
- * IconView is unaffected.
- *
- * When setting INVISIBLE, sets the visibility for the last selected child task.
- * When setting VISIBLE (as a reset), sets the visibility for both tasks.
- */
- @Override
- void setThumbnailVisibility(int visibility, int taskId) {
- if (visibility == VISIBLE) {
- mSnapshotView.setVisibility(visibility);
- mDigitalWellBeingToast.setBannerVisibility(visibility);
- mSnapshotView2.setVisibility(visibility);
- mDigitalWellBeingToast2.setBannerVisibility(visibility);
- } else if (taskId == getTaskIds()[0]) {
- mSnapshotView.setVisibility(visibility);
- mDigitalWellBeingToast.setBannerVisibility(visibility);
- } else {
- mSnapshotView2.setVisibility(visibility);
- mDigitalWellBeingToast2.setBannerVisibility(visibility);
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
new file mode 100644
index 0000000..93a7200
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -0,0 +1,529 @@
+/*
+ * 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.app.ActivityTaskManager.INVALID_TASK_ID
+import android.content.Context
+import android.graphics.PointF
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.util.Log
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewStub
+import com.android.internal.jank.Cuj
+import com.android.launcher3.Flags.enableOverviewIconMenu
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.util.CancellableTask
+import com.android.launcher3.util.RunnableList
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.TransformingTouchDelegate
+import com.android.quickstep.RecentsModel
+import com.android.quickstep.util.RecentsOrientedState
+import com.android.quickstep.util.SplitScreenUtils.Companion.convertLauncherSplitBoundsToShell
+import com.android.quickstep.util.SplitSelectStateController
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper
+import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition
+import java.util.function.Consumer
+
+/**
+ * TaskView that contains and shows thumbnails for not one, BUT TWO(!!) tasks
+ *
+ * That's right. If you call within the next 5 minutes we'll go ahead and double your order and send
+ * you !! TWO !! Tasks along with their TaskThumbnailViews complimentary. On. The. House. And not
+ * only that, we'll even clean up your thumbnail request if you don't like it. All the benefits of
+ * one TaskView, except DOUBLED!
+ *
+ * (Icon loading sold separately, fees may apply. Shipping & Handling for Overlays not included).
+ */
+class GroupedTaskView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) :
+ TaskView(context, attrs) {
+ // TODO(b/336612373): Support new TTV for GroupedTaskView
+ private val icon2CenterCoords = FloatArray(2)
+ private val digitalWellBeingToast2: DigitalWellBeingToast =
+ DigitalWellBeingToast(mContainer, this)
+ private lateinit var snapshotView2: TaskThumbnailViewDeprecated
+ private lateinit var iconView2: TaskViewIcon
+ private lateinit var icon2TouchDelegate: TransformingTouchDelegate
+ private var thumbnailLoadRequest2: CancellableTask<ThumbnailData>? = null
+ private var iconLoadRequest2: CancellableTask<*>? = null
+ var splitBoundsConfig: SplitConfigurationOptions.SplitBounds? = null
+ private set
+
+ @get:Deprecated("Use {@link #mTaskContainers} instead.")
+ private val secondTask: Task
+ /** Returns the second task bound to this TaskView. */
+ get() {
+ assert(mTaskContainers.size > 1) { "GroupedTaskView is not bound" }
+ return mTaskContainers[1].task
+ }
+
+ @get:PersistentSnapPosition
+ val snapPosition: Int
+ /** Returns the [PersistentSnapPosition] of this pair of tasks. */
+ get() {
+ checkNotNull(splitBoundsConfig) { "mSplitBoundsConfig is null" }
+ return splitBoundsConfig!!.snapPosition
+ }
+
+ override fun getThumbnailBounds(bounds: Rect, relativeToDragLayer: Boolean) {
+ splitBoundsConfig ?: return super.getThumbnailBounds(bounds, relativeToDragLayer)
+ if (relativeToDragLayer) {
+ val firstThumbnailBounds = Rect()
+ val secondThumbnailBounds = Rect()
+ with(mContainer.dragLayer) {
+ getDescendantRectRelativeToSelf(mTaskThumbnailViewDeprecated, firstThumbnailBounds)
+ getDescendantRectRelativeToSelf(snapshotView2, secondThumbnailBounds)
+ }
+ bounds.set(firstThumbnailBounds)
+ bounds.union(secondThumbnailBounds)
+ } else {
+ bounds.set(getSnapshotViewBounds(mTaskThumbnailViewDeprecated))
+ bounds.union(getSnapshotViewBounds(snapshotView2))
+ }
+ }
+
+ private fun getSnapshotViewBounds(snapshotView: View): Rect {
+ val snapshotViewX = Math.round(snapshotView.x)
+ val snapshotViewY = Math.round(snapshotView.y)
+ return Rect(
+ snapshotViewX,
+ snapshotViewY,
+ snapshotViewX + snapshotView.width,
+ snapshotViewY + snapshotView.height
+ )
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ snapshotView2 = findViewById(R.id.bottomright_snapshot)!!
+ val iconViewStub2 =
+ findViewById<ViewStub>(R.id.bottomRight_icon)!!.apply {
+ layoutResource =
+ if (enableOverviewIconMenu()) R.layout.icon_app_chip_view
+ else R.layout.icon_view
+ }
+ iconView2 = iconViewStub2.inflate() as TaskViewIcon
+ icon2TouchDelegate = TransformingTouchDelegate(iconView2.asView())
+ }
+
+ fun bind(
+ primaryTask: Task,
+ secondaryTask: Task,
+ orientedState: RecentsOrientedState,
+ splitBoundsConfig: SplitConfigurationOptions.SplitBounds?,
+ ) {
+ cancelPendingLoadTasks()
+ setupTaskContainers(primaryTask)
+ mTaskContainers =
+ listOf(
+ mTaskContainers[0].apply {
+ stagePosition = SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+ },
+ TaskContainer(
+ secondaryTask,
+ findViewById(R.id.bottomright_snapshot)!!,
+ iconView2,
+ SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT,
+ digitalWellBeingToast2
+ )
+ )
+ snapshotView2.bind(secondaryTask)
+ this.splitBoundsConfig = splitBoundsConfig
+ this.splitBoundsConfig?.let {
+ mTaskThumbnailViewDeprecated.previewPositionHelper.setSplitBounds(
+ convertLauncherSplitBoundsToShell(it),
+ PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT
+ )
+ snapshotView2.previewPositionHelper.setSplitBounds(
+ convertLauncherSplitBoundsToShell(it),
+ PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT
+ )
+ }
+ setOrientationState(orientedState)
+ }
+
+ /**
+ * Sets up an on-click listener and the visibility for show_windows icon on top of each task.
+ */
+ override fun setUpShowAllInstancesListener() {
+ // sets up the listener for the left/top task
+ super.setUpShowAllInstancesListener()
+ if (mTaskContainers.size < 2) {
+ return
+ }
+
+ // right/bottom task's base package name
+ val taskPackageName = mTaskContainers[1].task.key.packageName
+
+ // icon of the right/bottom task
+ val showWindowsView = findViewById<View>(R.id.show_windows_right)!!
+ updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName))
+ }
+
+ override fun onTaskListVisibilityChanged(visible: Boolean, changes: Int) {
+ super.onTaskListVisibilityChanged(visible, changes)
+ val model = RecentsModel.INSTANCE[context]
+ if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
+ if (visible) {
+ thumbnailLoadRequest2 =
+ model.thumbnailCache.updateThumbnailInBackground(secondTask) {
+ snapshotView2.setThumbnail(secondTask, it)
+ }
+ } else {
+ snapshotView2.setThumbnail(null, null)
+ // Reset the task thumbnail reference as well (it will be fetched from the cache or
+ // reloaded next time we need it)
+ secondTask.thumbnail = null
+ }
+ }
+ if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
+ if (visible) {
+ iconLoadRequest2 =
+ model.iconCache.updateIconInBackground(secondTask) {
+ setIcon(iconView2, it.icon)
+ if (enableOverviewIconMenu()) {
+ setText(iconView2, it.title)
+ }
+ digitalWellBeingToast2.initialize(secondTask)
+ digitalWellBeingToast2.setSplitConfiguration(splitBoundsConfig)
+ mDigitalWellBeingToast.setSplitConfiguration(splitBoundsConfig)
+ }
+ } else {
+ setIcon(iconView2, null)
+ if (enableOverviewIconMenu()) {
+ setText(iconView2, null)
+ }
+ }
+ }
+ }
+
+ fun updateSplitBoundsConfig(splitBounds: SplitConfigurationOptions.SplitBounds?) {
+ splitBoundsConfig = splitBounds
+ invalidate()
+ }
+
+ override fun offerTouchToChildren(event: MotionEvent): Boolean {
+ computeAndSetIconTouchDelegate(iconView2, icon2CenterCoords, icon2TouchDelegate)
+ return if (icon2TouchDelegate.onTouchEvent(event)) {
+ true
+ } else super.offerTouchToChildren(event)
+ }
+
+ override fun cancelPendingLoadTasks() {
+ super.cancelPendingLoadTasks()
+ thumbnailLoadRequest2?.cancel()
+ thumbnailLoadRequest2 = null
+ iconLoadRequest2?.cancel()
+ iconLoadRequest2 = null
+ }
+
+ override fun launchTaskAnimated(): RunnableList? {
+ if (mTaskContainers.isEmpty()) {
+ Log.d(TAG, "launchTaskAnimated - task is not bound")
+ return null
+ }
+ val recentsView = recentsView ?: return null
+ val endCallback = RunnableList()
+ // Callbacks run from remote animation when recents animation not currently running
+ InteractionJankMonitorWrapper.begin(
+ this,
+ Cuj.CUJ_SPLIT_SCREEN_ENTER,
+ "Enter form GroupedTaskView"
+ )
+ launchTaskInternal(isQuickSwitch = false, launchingExistingTaskView = true) {
+ endCallback.executeAllAndDestroy()
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER)
+ }
+
+ // Callbacks get run from recentsView for case when recents animation already running
+ recentsView.addSideTaskLaunchCallback(endCallback)
+ return endCallback
+ }
+
+ override fun launchTask(callback: Consumer<Boolean>, isQuickswitch: Boolean) {
+ launchTaskInternal(isQuickswitch, false, callback /*launchingExistingTaskview*/)
+ }
+
+ /**
+ * @param launchingExistingTaskView [SplitSelectStateController.launchExistingSplitPair] uses
+ * existence of GroupedTaskView as control flow of how to animate in the incoming task. If
+ * we're launching from overview (from overview thumbnails) then pass in `true`, otherwise
+ * pass in `false` for case like quickswitching from home to task
+ */
+ private fun launchTaskInternal(
+ isQuickSwitch: Boolean,
+ launchingExistingTaskView: Boolean,
+ callback: Consumer<Boolean>
+ ) {
+ check(mTaskContainers.size >= 2) { "task not bound" }
+ recentsView?.let {
+ it.splitSelectController.launchExistingSplitPair(
+ if (launchingExistingTaskView) this else null,
+ mTaskContainers[0].task.key.id,
+ mTaskContainers[1].task.key.id,
+ SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
+ callback,
+ isQuickSwitch,
+ snapPosition
+ )
+ Log.d(TAG, "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}")
+ }
+ }
+
+ public override fun refreshThumbnails(thumbnailDatas: HashMap<Int, ThumbnailData?>?) {
+ super.refreshThumbnails(thumbnailDatas)
+ thumbnailDatas?.get(secondTask.key.id)?.let { snapshotView2.setThumbnail(secondTask, it) }
+ ?: { snapshotView2.refresh() }
+ }
+
+ /**
+ * Returns taskId that split selection was initiated with, [INVALID_TASK_ID] if no tasks in this
+ * TaskView are part of split selection
+ */
+ private fun getThisTaskCurrentlyInSplitSelection(): Int {
+ val initialTaskId = recentsView?.splitSelectController?.initialTaskId
+ return if (initialTaskId != null && containsTaskId(initialTaskId)) initialTaskId
+ else INVALID_TASK_ID
+ }
+
+ override fun getLastSelectedChildTaskIndex(): Int {
+ if (recentsView?.splitSelectController?.isDismissingFromSplitPair == true) {
+ // return the container index of the task that wasn't initially selected to split
+ // with because that is the only remaining app that can be selected. The coordinate
+ // checks below aren't reliable since both of those views may be gone/transformed
+ val initSplitTaskId = getThisTaskCurrentlyInSplitSelection()
+ if (initSplitTaskId != INVALID_TASK_ID) {
+ return if (initSplitTaskId == firstTask!!.key.id) 1 else 0
+ }
+ }
+
+ // Check which of the two apps was selected
+ if (
+ iconView2.asView().containsPoint(mLastTouchDownPosition) ||
+ snapshotView2.containsPoint(mLastTouchDownPosition)
+ ) {
+ return 1
+ }
+ return super.getLastSelectedChildTaskIndex()
+ }
+
+ private fun View.containsPoint(position: PointF): Boolean {
+ val localPos = floatArrayOf(position.x, position.y)
+ Utilities.mapCoordInSelfToDescendant(this, this@GroupedTaskView, localPos)
+ return Utilities.pointInView(this, localPos[0], localPos[1], 0f /* slop */)
+ }
+
+ override fun onRecycle() {
+ super.onRecycle()
+ snapshotView2.setThumbnail(secondTask, null)
+ splitBoundsConfig = null
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ val widthSize = MeasureSpec.getSize(widthMeasureSpec)
+ val heightSize = MeasureSpec.getSize(heightMeasureSpec)
+ setMeasuredDimension(widthSize, heightSize)
+ val splitBoundsConfig = splitBoundsConfig ?: return
+ val initSplitTaskId = getThisTaskCurrentlyInSplitSelection()
+ if (initSplitTaskId == INVALID_TASK_ID) {
+ pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds(
+ mTaskThumbnailViewDeprecated,
+ snapshotView2,
+ widthSize,
+ heightSize,
+ splitBoundsConfig,
+ mContainer.deviceProfile,
+ layoutDirection == LAYOUT_DIRECTION_RTL
+ )
+ // Should we be having a separate translation step apart from the measuring above?
+ // The following only applies to large screen for now, but for future reference
+ // we'd want to abstract this out in PagedViewHandlers to get the primary/secondary
+ // translation directions
+ mTaskThumbnailViewDeprecated.applySplitSelectTranslateX(
+ mTaskThumbnailViewDeprecated.translationX
+ )
+ mTaskThumbnailViewDeprecated.applySplitSelectTranslateY(
+ mTaskThumbnailViewDeprecated.translationY
+ )
+ snapshotView2.applySplitSelectTranslateX(snapshotView2.translationX)
+ snapshotView2.applySplitSelectTranslateY(snapshotView2.translationY)
+ } else {
+ // Currently being split with this taskView, let the non-split selected thumbnail
+ // take up full thumbnail area
+ mTaskContainers
+ .firstOrNull { it.task.key.id != initSplitTaskId }
+ ?.thumbnailView
+ ?.measure(
+ widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(
+ heightSize - mContainer.deviceProfile.overviewTaskThumbnailTopMarginPx,
+ MeasureSpec.EXACTLY
+ )
+ )
+ }
+ if (!enableOverviewIconMenu()) {
+ updateIconPlacement()
+ }
+ }
+
+ override fun setOverlayEnabled(overlayEnabled: Boolean) {
+ if (FeatureFlags.enableAppPairs()) {
+ super.setOverlayEnabled(overlayEnabled)
+ } else {
+ // Intentional no-op to prevent setting smart actions overlay on thumbnails
+ }
+ }
+
+ override fun setOrientationState(orientationState: RecentsOrientedState) {
+ if (enableOverviewIconMenu()) {
+ splitBoundsConfig?.let {
+ val groupedTaskViewSizes =
+ orientationState.orientationHandler.getGroupedTaskViewSizes(
+ mContainer.deviceProfile,
+ it,
+ layoutParams.width,
+ layoutParams.height
+ )
+ val iconViewMarginStart =
+ resources.getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_expanded_top_start_margin
+ )
+ val iconViewBackgroundMarginStart =
+ resources.getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_background_margin_top_start
+ )
+ val iconMargins = (iconViewMarginStart + iconViewBackgroundMarginStart) * 2
+ // setMaxWidth() needs to be called before mIconView.setIconOrientation which is
+ // called in the super below.
+ (mIconView as IconAppChipView).setMaxWidth(
+ groupedTaskViewSizes.first.x - iconMargins
+ )
+ (iconView2 as IconAppChipView).setMaxWidth(
+ groupedTaskViewSizes.second.x - iconMargins
+ )
+ }
+ }
+ super.setOrientationState(orientationState)
+ iconView2.setIconOrientation(orientationState, isGridTask())
+ updateIconPlacement()
+ }
+
+ override fun setThumbnailOrientation(orientationState: RecentsOrientedState?) {
+ super.setThumbnailOrientation(orientationState)
+ digitalWellBeingToast2.initialize(secondTask)
+ }
+
+ private fun updateIconPlacement() {
+ val splitBoundsConfig = splitBoundsConfig ?: return
+ val taskIconHeight = mContainer.deviceProfile.overviewTaskIconSizePx
+ val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
+ if (enableOverviewIconMenu()) {
+ val groupedTaskViewSizes =
+ pagedOrientationHandler.getGroupedTaskViewSizes(
+ mContainer.deviceProfile,
+ splitBoundsConfig,
+ layoutParams.width,
+ layoutParams.height
+ )
+ pagedOrientationHandler.setSplitIconParams(
+ mIconView.asView(),
+ iconView2.asView(),
+ taskIconHeight,
+ groupedTaskViewSizes.first.x,
+ groupedTaskViewSizes.first.y,
+ layoutParams.height,
+ layoutParams.width,
+ isRtl,
+ mContainer.deviceProfile,
+ splitBoundsConfig
+ )
+ } else {
+ pagedOrientationHandler.setSplitIconParams(
+ mIconView.asView(),
+ iconView2.asView(),
+ taskIconHeight,
+ mTaskThumbnailViewDeprecated.measuredWidth,
+ mTaskThumbnailViewDeprecated.measuredHeight,
+ measuredHeight,
+ measuredWidth,
+ isRtl,
+ mContainer.deviceProfile,
+ splitBoundsConfig
+ )
+ }
+ }
+
+ override fun updateSnapshotRadius() {
+ super.updateSnapshotRadius()
+ snapshotView2.setFullscreenParams(mCurrentFullscreenParams)
+ }
+
+ override fun setIconsAndBannersTransitionProgress(progress: Float, invert: Boolean) {
+ super.setIconsAndBannersTransitionProgress(progress, invert)
+ // Value set by super call
+ val scale = mIconView.alpha
+ iconView2.setContentAlpha(scale)
+ digitalWellBeingToast2.updateBannerOffset(1f - scale)
+ }
+
+ override fun setColorTint(amount: Float, tintColor: Int) {
+ super.setColorTint(amount, tintColor)
+ iconView2.setIconColorTint(tintColor, amount)
+ snapshotView2.dimAlpha = amount
+ digitalWellBeingToast2.setBannerColorTint(tintColor, amount)
+ }
+
+ override fun applyThumbnailSplashAlpha() {
+ super.applyThumbnailSplashAlpha()
+ snapshotView2.setSplashAlpha(mTaskThumbnailSplashAlpha)
+ }
+
+ override fun refreshTaskThumbnailSplash() {
+ super.refreshTaskThumbnailSplash()
+ snapshotView2.refreshSplashView()
+ }
+
+ override fun resetViewTransforms() {
+ super.resetViewTransforms()
+ snapshotView2.resetViewTransforms()
+ }
+
+ /**
+ * Sets visibility for thumbnails and associated elements (DWB banners). IconView is unaffected.
+ *
+ * When setting INVISIBLE, sets the visibility for the last selected child task. When setting
+ * VISIBLE (as a reset), sets the visibility for both tasks.
+ */
+ public override fun setThumbnailVisibility(visibility: Int, taskId: Int) {
+ mTaskContainers.forEach {
+ if (visibility == VISIBLE || it.task.key.id == taskId) {
+ it.thumbnailView.visibility = visibility
+ it.digitalWellBeingToast.setBannerVisibility(visibility)
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "GroupedTaskView"
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 5188d4a..83a2ceb 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -33,9 +33,8 @@
import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.NavigationMode;
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
@@ -43,13 +42,13 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
/**
* View for showing action buttons in Overview
*/
public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
implements OnClickListener, Insettable {
-
private final Rect mInsets = new Rect();
@IntDef(flag = true, value = {
@@ -89,30 +88,30 @@
private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
private static final int INDEX_SHARE_TARGET_ALPHA = 4;
private static final int INDEX_SCROLL_ALPHA = 5;
- private static final int NUM_ALPHAS = 6;
-
- public @interface ScreenshotButtonHiddenFlags { }
- public static final int FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 << 0;
+ private static final int INDEX_GROUPED_ALPHA = 6;
+ private static final int INDEX_3P_LAUNCHER = 7;
+ private static final int NUM_ALPHAS = 8;
public @interface SplitButtonHiddenFlags { }
public static final int FLAG_SMALL_SCREEN_HIDE_SPLIT = 1 << 0;
- public static final int FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 << 1;
- public @interface SplitButtonDisabledFlags { }
- public static final int FLAG_SINGLE_TASK_DISABLE_SPLIT = 1 << 0;
+ /**
+ * Holds an AnimatedFloat for each alpha property, used to set or animate alpha values in
+ * {@link #mMultiValueAlphas}.
+ */
+ private final AnimatedFloat[] mAlphaProperties = new AnimatedFloat[NUM_ALPHAS];
- public @interface AppPairButtonHiddenFlags { }
- public static final int FLAG_SINGLE_TASK_HIDE_APP_PAIR = 1 << 0;
- public static final int FLAG_SMALL_SCREEN_HIDE_APP_PAIR = 1 << 1;
- public static final int FLAG_3P_LAUNCHER_HIDE_APP_PAIR = 1 << 2;
+ /** Holds MultiValueAlpha values for all actions bars */
+ private final MultiValueAlpha[] mMultiValueAlphas = new MultiValueAlpha[2];
+ /** Index used for single-task actions in the mMultiValueAlphas array */
+ private static final int ACTIONS_ALPHAS = 0;
+ /** Index used for grouped-task actions in the mMultiValueAlphas array */
+ private static final int GROUP_ACTIONS_ALPHAS = 1;
- private MultiValueAlpha mMultiValueAlpha;
-
+ /** Container for the action buttons below a focused, non-split Overview tile. */
protected LinearLayout mActionButtons;
- // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is an
- // ImageButton in go launcher (does not share a common class with Button). Take care when
- // casting this.
- private View mScreenshotButton;
+ /** Container for the action buttons below a focused, split Overview tile. */
+ protected LinearLayout mGroupActionButtons;
private Button mSplitButton;
private Button mSaveAppPairButton;
@@ -122,21 +121,17 @@
@ActionsDisabledFlags
protected int mDisabledFlags;
- @ScreenshotButtonHiddenFlags
- private int mScreenshotButtonHiddenFlags;
-
@SplitButtonHiddenFlags
private int mSplitButtonHiddenFlags;
- @AppPairButtonHiddenFlags
- private int mAppPairButtonHiddenFlags;
-
@Nullable
protected T mCallbacks;
@Nullable
protected DeviceProfile mDp;
private final Rect mTaskSize = new Rect();
+ private boolean mIsGroupedTask = false;
+ private boolean mCanSaveAppPair = false;
public OverviewActionsView(Context context) {
this(context, null);
@@ -153,12 +148,31 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ // Initialize 2 view containers: one for single tasks, one for grouped tasks.
+ // These will take up the same space on the screen and alternate visibility as needed.
mActionButtons = findViewById(R.id.action_buttons);
- mMultiValueAlpha = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
- mMultiValueAlpha.setUpdateVisibility(true);
+ mGroupActionButtons = findViewById(R.id.group_action_buttons);
+ // Initialize a list to hold alphas for mActionButtons and mGroupActionButtons.
+ mMultiValueAlphas[ACTIONS_ALPHAS] = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
+ mMultiValueAlphas[GROUP_ACTIONS_ALPHAS] =
+ new MultiValueAlpha(mGroupActionButtons, NUM_ALPHAS);
+ Arrays.stream(mMultiValueAlphas).forEach(a -> a.setUpdateVisibility(true));
+ // To control alpha simultaneously on mActionButtons and mGroupActionButtons, we set up an
+ // AnimatedFloat for each alpha property.
+ for (int i = 0; i < NUM_ALPHAS; i++) {
+ final int index = i;
+ mAlphaProperties[index] = new AnimatedFloat(() -> {
+ for (MultiValueAlpha multiValueAlpha : mMultiValueAlphas) {
+ multiValueAlpha.get(index).setValue(mAlphaProperties[index].value);
+ }
+ }, 1f /* initialValue */);
+ }
- mScreenshotButton = findViewById(R.id.action_screenshot);
- mScreenshotButton.setOnClickListener(this);
+ // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is
+ // an ImageButton in go launcher (does not share a common class with Button). Take care when
+ // casting this.
+ View screenshotButton = findViewById(R.id.action_screenshot);
+ screenshotButton.setOnClickListener(this);
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
@@ -209,7 +223,7 @@
mHiddenFlags &= ~visibilityFlags;
}
boolean isHidden = mHiddenFlags != 0;
- mMultiValueAlpha.get(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
+ mAlphaProperties[INDEX_HIDDEN_FLAGS_ALPHA].updateValue(isHidden ? 0 : 1);
}
/**
@@ -234,14 +248,13 @@
* Updates a batch of flags to hide and show actions buttons when a grouped task (split screen)
* is focused.
* @param isGroupedTask True if the focused task is a grouped task.
+ * @param canSaveAppPair True if the focused task is a grouped task and can be saved as an app
+ * pair.
*/
- public void updateForGroupedTask(boolean isGroupedTask) {
- // Update flags to see if split button should be hidden.
- updateSplitButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, isGroupedTask);
- // Update flags to see if screenshot button should be hidden.
- updateScreenshotButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, isGroupedTask);
- // Update flags to see if save app pair button should be hidden.
- updateAppPairButtonHiddenFlags(FLAG_SINGLE_TASK_HIDE_APP_PAIR, !isGroupedTask);
+ public void updateForGroupedTask(boolean isGroupedTask, boolean canSaveAppPair) {
+ mIsGroupedTask = isGroupedTask;
+ mCanSaveAppPair = canSaveAppPair;
+ updateActionButtonsVisibility();
}
/**
@@ -251,36 +264,30 @@
assert mDp != null;
// Update flags to see if split button should be hidden.
updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, !mDp.isTablet);
- // Update flags to see if save app pair button should be hidden.
- updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, !mDp.isTablet);
+ updateActionButtonsVisibility();
+ }
+
+ private void updateActionButtonsVisibility() {
+ assert mDp != null;
+ boolean showSingleTaskActions = !mIsGroupedTask;
+ boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair;
+ getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0);
+ getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0);
}
/**
* Updates flags to hide and show actions buttons for 1p/3p launchers.
*/
public void updateFor3pLauncher(boolean is3pLauncher) {
- updateAppPairButtonHiddenFlags(FLAG_3P_LAUNCHER_HIDE_APP_PAIR, is3pLauncher);
+ getGroupActionsAlphas().get(INDEX_3P_LAUNCHER).setValue(is3pLauncher ? 0 : 1);
}
- /**
- * Updates the proper flags to indicate whether the "Screenshot" button should be hidden.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
- */
- private void updateScreenshotButtonHiddenFlags(@ScreenshotButtonHiddenFlags int flag,
- boolean enable) {
- if (mScreenshotButton == null) return;
- if (enable) {
- mScreenshotButtonHiddenFlags |= flag;
- } else {
- mScreenshotButtonHiddenFlags &= ~flag;
- }
- int desiredVisibility = mScreenshotButtonHiddenFlags == 0 ? VISIBLE : GONE;
- if (mScreenshotButton.getVisibility() != desiredVisibility) {
- mScreenshotButton.setVisibility(desiredVisibility);
- mActionButtons.requestLayout();
- }
+ private MultiValueAlpha getActionsAlphas() {
+ return mMultiValueAlphas[ACTIONS_ALPHAS];
+ }
+
+ private MultiValueAlpha getGroupActionsAlphas() {
+ return mMultiValueAlphas[GROUP_ACTIONS_ALPHAS];
}
/**
@@ -304,56 +311,32 @@
}
}
- /**
- * Updates the proper flags to indicate whether the "Save app pair" button should be disabled.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
- */
- private void updateAppPairButtonHiddenFlags(
- @AppPairButtonHiddenFlags int flag, boolean enable) {
- if (!FeatureFlags.enableAppPairs()) {
- return;
- }
-
- if (mSaveAppPairButton == null) return;
- if (enable) {
- mAppPairButtonHiddenFlags |= flag;
- } else {
- mAppPairButtonHiddenFlags &= ~flag;
- }
- int desiredVisibility = mAppPairButtonHiddenFlags == 0 ? VISIBLE : GONE;
- if (mSaveAppPairButton.getVisibility() != desiredVisibility) {
- mSaveAppPairButton.setVisibility(desiredVisibility);
- mActionButtons.requestLayout();
- }
+ public AnimatedFloat getContentAlpha() {
+ return mAlphaProperties[INDEX_CONTENT_ALPHA];
}
- public MultiProperty getContentAlpha() {
- return mMultiValueAlpha.get(INDEX_CONTENT_ALPHA);
+ public AnimatedFloat getVisibilityAlpha() {
+ return mAlphaProperties[INDEX_VISIBILITY_ALPHA];
}
- public MultiProperty getVisibilityAlpha() {
- return mMultiValueAlpha.get(INDEX_VISIBILITY_ALPHA);
+ public AnimatedFloat getFullscreenAlpha() {
+ return mAlphaProperties[INDEX_FULLSCREEN_ALPHA];
}
- public MultiProperty getFullscreenAlpha() {
- return mMultiValueAlpha.get(INDEX_FULLSCREEN_ALPHA);
+ public AnimatedFloat getShareTargetAlpha() {
+ return mAlphaProperties[INDEX_SHARE_TARGET_ALPHA];
}
- public MultiProperty getShareTargetAlpha() {
- return mMultiValueAlpha.get(INDEX_SHARE_TARGET_ALPHA);
- }
-
- public MultiProperty getIndexScrollAlpha() {
- return mMultiValueAlpha.get(INDEX_SCROLL_ALPHA);
+ public AnimatedFloat getIndexScrollAlpha() {
+ return mAlphaProperties[INDEX_SCROLL_ALPHA];
}
/**
* Returns the visibility of the overview actions buttons.
*/
- public @Visibility int getActionsButtonVisibility() {
- return mActionButtons.getVisibility();
+ public boolean areActionsButtonsVisible() {
+ return mActionButtons.getVisibility() == View.VISIBLE
+ || mGroupActionButtons.getVisibility() == View.VISIBLE;
}
/**
@@ -366,10 +349,17 @@
/** Updates vertical margins for different navigation mode or configuration changes. */
public void updateVerticalMargin(NavigationMode mode) {
+ updateActionBarPosition(mActionButtons);
+ updateActionBarPosition(mGroupActionButtons);
+ }
+
+ /** Positions actions buttons according to device settings and insets. */
+ private void updateActionBarPosition(LinearLayout actionBar) {
if (mDp == null) {
return;
}
- LayoutParams actionParams = (LayoutParams) mActionButtons.getLayoutParams();
+
+ LayoutParams actionParams = (LayoutParams) actionBar.getLayoutParams();
actionParams.setMargins(
actionParams.leftMargin, mDp.overviewActionsTopMarginPx,
actionParams.rightMargin, getBottomMargin());
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index ae6f703..731b839 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -35,6 +35,7 @@
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
+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.LauncherState.BACKGROUND_APP;
@@ -130,6 +131,7 @@
import com.android.internal.jank.Cuj;
import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.PagedView;
@@ -185,6 +187,7 @@
import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.recents.viewmodel.RecentsViewData;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AnimUtils;
@@ -203,7 +206,7 @@
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.VibrationConstants;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -375,6 +378,9 @@
public void setValue(RecentsView view, float scale) {
view.setScaleX(scale);
view.setScaleY(scale);
+ if (enableRefactorTaskThumbnail()) {
+ view.mRecentsViewData.getScale().setValue(scale);
+ }
view.mLastComputedTaskStartPushOutDistance = null;
view.mLastComputedTaskEndPushOutDistance = null;
view.runActionOnRemoteHandles(new Consumer<RemoteTargetHandle>() {
@@ -445,6 +451,8 @@
private static final float FOREGROUND_SCRIM_TINT = 0.32f;
+ public final RecentsViewData mRecentsViewData = new RecentsViewData();
+
protected final RecentsOrientedState mOrientationState;
protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
@Nullable
@@ -590,7 +598,7 @@
if (taskView == null) {
return;
}
- Task.TaskKey taskKey = taskView.getTask().key;
+ Task.TaskKey taskKey = taskView.getFirstTask().key;
UI_HELPER_EXECUTOR.execute(new CancellableTask<>(
() -> PackageManagerWrapper.getInstance()
.getActivityInfo(taskKey.getComponent(), taskKey.userId) == null,
@@ -625,7 +633,6 @@
*/
protected int mRunningTaskViewId = -1;
private int mTaskViewIdCount;
- private final int[] INVALID_TASK_IDS = new int[]{-1, -1};
protected boolean mRunningTaskTileHidden;
@Nullable
private Task[] mTmpRunningTasks;
@@ -770,6 +777,8 @@
// keeps track of the state of the filter for tasks in recents view
private final RecentsFilterState mFilterState = new RecentsFilterState();
+ private int mOffsetMidpointIndexOverride = INVALID_PAGE;
+
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
BaseContainerInterface sizeStrategy) {
super(context, attrs, defStyleAttr);
@@ -989,8 +998,7 @@
if (mHandleTaskStackChanges) {
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
- for (TaskIdAttributeContainer container :
- taskView.getTaskIdAttributeContainers()) {
+ for (TaskContainer container : taskView.getTaskContainers()) {
if (container == null || taskId != container.getTask().key.id) {
continue;
}
@@ -1005,11 +1013,12 @@
public void onTaskIconChanged(String pkg, UserHandle user) {
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView tv = requireTaskViewAt(i);
- Task task = tv.getTask();
+ Task task = tv.getFirstTask();
if (task != null && task.key != null && pkg.equals(task.key.getPackageName())
&& task.key.userId == user.getIdentifier()) {
task.icon = null;
- if (tv.getIconView().getDrawable() != null) {
+ TaskViewIcon firstIconView = tv.getFirstIconView();
+ if (firstIconView != null && firstIconView.getDrawable() != null) {
tv.onTaskListVisibilityChanged(true /* visible */);
}
}
@@ -1040,13 +1049,14 @@
continue;
}
// taskView could be a GroupedTaskView, so select the relevant task by ID
- TaskIdAttributeContainer taskAttributes = taskView.getTaskAttributesById(id);
+ TaskContainer taskAttributes = taskView.getTaskContainerById(id);
if (taskAttributes == null) {
continue;
}
Task task = taskAttributes.getTask();
- TaskThumbnailView taskThumbnailView = taskAttributes.getThumbnailView();
- taskThumbnailView.setThumbnail(task, thumbnail, refreshNow);
+ TaskThumbnailViewDeprecated taskThumbnailViewDeprecated =
+ taskAttributes.getThumbnailView();
+ taskThumbnailViewDeprecated.setThumbnail(task, thumbnail, refreshNow);
// thumbnailData can contain 1-2 ids, but they should correspond to the same
// TaskView, so overwriting is ok
updatedTaskView = taskView;
@@ -1411,7 +1421,7 @@
*/
@Nullable
public TaskView getTaskViewByTaskIds(int[] taskIds) {
- if (!hasAnyValidTaskIds(taskIds)) {
+ if (!hasAllValidTaskIds(taskIds)) {
return null;
}
@@ -1430,9 +1440,11 @@
return null;
}
- /** Returns false if {@code taskIds} is null or contains invalid values, true otherwise */
- private boolean hasAnyValidTaskIds(int[] taskIds) {
- return taskIds != null && !Arrays.equals(taskIds, INVALID_TASK_IDS);
+ /** Returns false if {@code taskIds} is null or contains any invalid values, true otherwise */
+ private boolean hasAllValidTaskIds(int[] taskIds) {
+ return taskIds != null
+ && taskIds.length > 0
+ && Arrays.stream(taskIds).noneMatch(taskId -> taskId == INVALID_TASK_ID);
}
public void setOverviewStateEnabled(boolean enabled) {
@@ -1705,6 +1717,12 @@
return;
}
+ if (taskGroups == null) {
+ Log.d(TAG, "applyLoadPlan - taskGroups is null");
+ } else {
+ Log.d(TAG, "applyLoadPlan - taskGroups: " + taskGroups.stream().map(
+ GroupTask::toString).toList());
+ }
mLoadPlanEverApplied = true;
if (taskGroups == null || taskGroups.isEmpty()) {
removeTasksViewsAndClearAllButton();
@@ -1718,10 +1736,12 @@
return;
}
- int[] currentTaskId = INVALID_TASK_IDS;
+ int[] currentTaskIds;
TaskView currentTaskView = getTaskViewAt(mCurrentPage);
- if (currentTaskView != null && currentTaskView.getTask() != null) {
- currentTaskId = currentTaskView.getTaskIds();
+ if (currentTaskView != null && currentTaskView.getFirstTask() != null) {
+ currentTaskIds = currentTaskView.getTaskIds();
+ } else {
+ currentTaskIds = new int[0];
}
// Unload existing visible task data
@@ -1733,8 +1753,8 @@
// Save running task ID if it exists before rebinding all taskViews, otherwise the task from
// the runningTaskView currently bound could get assigned to another TaskView
- int[] runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId);
- int[] focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId);
+ int[] runningTaskIds = getTaskIdsForTaskViewId(mRunningTaskViewId);
+ int[] focusedTaskIds = getTaskIdsForTaskViewId(mFocusedTaskViewId);
// 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.
@@ -1817,7 +1837,7 @@
}
// Keep same previous focused task
- TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskId);
+ TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskIds);
// If the list changed, maybe the focused task doesn't exist anymore
if (newFocusedTaskView == null && getTaskViewCount() > 0) {
newFocusedTaskView = getTaskViewAt(0);
@@ -1828,12 +1848,12 @@
updateChildTaskOrientations();
TaskView newRunningTaskView = null;
- if (hasAnyValidTaskIds(runningTaskId)) {
+ if (hasAllValidTaskIds(runningTaskIds)) {
// Update mRunningTaskViewId to be the new TaskView that was assigned by binding
// the full list of tasks to taskViews
- newRunningTaskView = getTaskViewByTaskIds(runningTaskId);
+ newRunningTaskView = getTaskViewByTaskIds(runningTaskIds);
if (newRunningTaskView != null) {
- mRunningTaskViewId = newRunningTaskView.getTaskViewId();
+ setRunningTaskViewId(newRunningTaskView.getTaskViewId());
} else {
if (mActiveGestureRunningTasks != null) {
// This will update mRunningTaskViewId and create a stub view if necessary.
@@ -1842,7 +1862,7 @@
// the current running task is excludedFromRecents.)
showCurrentTask(mActiveGestureRunningTasks);
} else {
- mRunningTaskViewId = INVALID_TASK_ID;
+ setRunningTaskViewId(INVALID_TASK_ID);
}
}
}
@@ -1851,8 +1871,8 @@
if (mNextPage != INVALID_PAGE) {
// Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll.
mCurrentPage = previousCurrentPage;
- if (hasAnyValidTaskIds(currentTaskId)) {
- currentTaskView = getTaskViewByTaskIds(currentTaskId);
+ if (hasAllValidTaskIds(currentTaskIds)) {
+ currentTaskView = getTaskViewByTaskIds(currentTaskIds);
if (currentTaskView != null) {
targetPage = indexOfChild(currentTaskView);
}
@@ -1861,7 +1881,7 @@
targetPage = previousFocusedPage;
} else {
// Set the current page to the running task, but not if settling on new task.
- if (hasAnyValidTaskIds(runningTaskId)) {
+ if (hasAllValidTaskIds(runningTaskIds)) {
targetPage = indexOfChild(newRunningTaskView);
} else if (getTaskViewCount() > 0) {
targetPage = indexOfChild(requireTaskViewAt(0));
@@ -1961,7 +1981,8 @@
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
TaskView taskView = requireTaskViewAt(i);
- if (mIgnoreResetTaskId != taskView.getTaskIds()[0]) {
+ if (Arrays.stream(taskView.getTaskIds()).noneMatch(
+ taskId -> taskId == mIgnoreResetTaskId)) {
taskView.resetViewTransforms();
taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
taskView.setStableAlpha(mContentAlpha);
@@ -1998,6 +2019,9 @@
public void setFullscreenProgress(float fullscreenProgress) {
mFullscreenProgress = fullscreenProgress;
+ if (enableRefactorTaskThumbnail()) {
+ mRecentsViewData.getFullscreenProgress().setValue(mFullscreenProgress);
+ }
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
@@ -2005,7 +2029,7 @@
mClearAllButton.setFullscreenProgress(fullscreenProgress);
// Fade out the actions view quickly (0.1 range)
- mActionsView.getFullscreenAlpha().setValue(
+ mActionsView.getFullscreenAlpha().updateValue(
mapToRange(fullscreenProgress, 0, 0.1f, 1f, 0f, LINEAR));
}
@@ -2256,8 +2280,8 @@
}
private void animateActionsViewAlpha(float alphaValue, long duration) {
- mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(
- mActionsView.getVisibilityAlpha(), MULTI_PROPERTY_VALUE, alphaValue);
+ mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(mActionsView.getVisibilityAlpha(),
+ AnimatedFloat.VALUE, alphaValue);
mActionsViewAlphaAnimatorFinalValue = alphaValue;
mActionsViewAlphaAnimator.setDuration(duration);
// Set autocancel to prevent race-conditiony setting of alpha from other animations
@@ -2276,7 +2300,7 @@
mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled);
// Clear all button alpha was set by the previous line.
- mActionsView.getIndexScrollAlpha().setValue(1 - mClearAllButton.getScrollAlpha());
+ mActionsView.getIndexScrollAlpha().updateValue(1 - mClearAllButton.getScrollAlpha());
}
@Override
@@ -2340,8 +2364,8 @@
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = requireTaskViewAt(i);
- TaskIdAttributeContainer[] containers = taskView.getTaskIdAttributeContainers();
- if (containers[0] == null && containers[1] == null) {
+ List<TaskContainer> containers = taskView.getTaskContainers();
+ if (containers.isEmpty()) {
continue;
}
int index = indexOfChild(taskView);
@@ -2353,8 +2377,8 @@
}
if (visible) {
// Default update all non-null tasks, then remove running ones
- List<Task> tasksToUpdate = Arrays.stream(containers).filter(Objects::nonNull)
- .map(TaskIdAttributeContainer::getTask)
+ List<Task> tasksToUpdate = containers.stream()
+ .map(TaskContainer::getTask)
.collect(Collectors.toCollection(ArrayList::new));
if (mTmpRunningTasks != null) {
for (Task t : mTmpRunningTasks) {
@@ -2379,7 +2403,7 @@
mHasVisibleTaskData.put(task.key.id, visible);
}
} else {
- for (TaskIdAttributeContainer container : containers) {
+ for (TaskContainer container : containers) {
if (container == null) {
continue;
}
@@ -2496,7 +2520,7 @@
// For now 2 distinct task IDs is max for split screen
TaskView runningTaskView = getTaskViewFromTaskViewId(taskViewId);
if (runningTaskView == null) {
- return INVALID_TASK_IDS;
+ return new int[0];
}
return runningTaskView.getTaskIds();
@@ -2585,7 +2609,7 @@
*/
public void onGestureAnimationStart(
Task[] runningTasks, RotationTouchHelper rotationTouchHelper) {
- Log.d(TAG, "onGestureAnimationStart");
+ Log.d(TAG, "onGestureAnimationStart - runningTasks: " + Arrays.toString(runningTasks));
mActiveGestureRunningTasks = runningTasks;
// This needs to be called before the other states are set since it can create the task view
if (mOrientationState.setGestureActive(true)) {
@@ -2734,18 +2758,19 @@
* Returns true if we should add a stub taskView for the running task id
*/
protected boolean shouldAddStubTaskView(Task[] runningTasks) {
- if (runningTasks.length > 1) {
- TaskView primaryTaskView = getTaskViewByTaskId(runningTasks[0].key.id);
- TaskView secondaryTaskView = getTaskViewByTaskId(runningTasks[1].key.id);
- int leftTopTaskViewId =
- (primaryTaskView == null) ? -1 : primaryTaskView.getTaskViewId();
- int rightBottomTaskViewId =
- (secondaryTaskView == null) ? -1 : secondaryTaskView.getTaskViewId();
- // Add a new stub view if both taskIds don't match any taskViews
- return leftTopTaskViewId != rightBottomTaskViewId || leftTopTaskViewId == -1;
+ int[] runningTaskIds = Arrays.stream(runningTasks).mapToInt(task -> task.key.id).toArray();
+ TaskView matchingTaskView = null;
+ if (hasDesktopTask(runningTasks) && runningTaskIds.length == 1) {
+ // TODO(b/249371338): Unsure if it's expected, desktop runningTasks only have a single
+ // taskId, therefore we match any DesktopTaskView that contains the runningTaskId.
+ TaskView taskview = getTaskViewByTaskId(runningTaskIds[0]);
+ if (taskview instanceof DesktopTaskView) {
+ matchingTaskView = taskview;
+ }
+ } else {
+ matchingTaskView = getTaskViewByTaskIds(runningTaskIds);
}
- Task runningTaskInfo = runningTasks[0];
- return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.key.id) == null;
+ return matchingTaskView == null;
}
/**
@@ -2755,6 +2780,7 @@
* is called. Also scrolls the view to this task.
*/
private void showCurrentTask(Task[] runningTasks) {
+ Log.d(TAG, "showCurrentTask - runningTasks: " + Arrays.toString(runningTasks));
if (runningTasks.length == 0) {
return;
}
@@ -2842,7 +2868,23 @@
setRunningTaskViewShowScreenshot(true);
setRunningTaskHidden(false);
}
+ setRunningTaskViewId(runningTaskViewId);
+ }
+
+ private void setRunningTaskViewId(int runningTaskViewId) {
+ int prevRunningTaskViewId = mRunningTaskViewId;
mRunningTaskViewId = runningTaskViewId;
+
+ if (Flags.enableRefactorTaskThumbnail()) {
+ TaskView previousRunningTaskView = getTaskViewFromTaskViewId(prevRunningTaskViewId);
+ if (previousRunningTaskView != null) {
+ previousRunningTaskView.notifyIsRunningTaskUpdated();
+ }
+ TaskView newRunningTaskView = getTaskViewFromTaskViewId(runningTaskViewId);
+ if (newRunningTaskView != null) {
+ newRunningTaskView.notifyIsRunningTaskUpdated();
+ }
+ }
}
private int getTaskViewIdFromTaskId(int taskId) {
@@ -3784,7 +3826,7 @@
if (success) {
if (shouldRemoveTask) {
- if (dismissedTaskView.getTask() != null) {
+ if (dismissedTaskView.getFirstTask() != null) {
if (dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
() -> removeTaskInternal(dismissedTaskViewId));
@@ -3979,7 +4021,9 @@
* * Device is large screen
*/
private void updateCurrentTaskActionsVisibility() {
- boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
+ TaskView taskView = getCurrentPageTaskView();
+ boolean isCurrentSplit = taskView instanceof GroupedTaskView;
+ GroupedTaskView groupedTaskView = isCurrentSplit ? (GroupedTaskView) taskView : null;
// Update flags to see if entire actions bar should be hidden.
if (!FeatureFlags.enableAppPairs()) {
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
@@ -3987,9 +4031,11 @@
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
// Update flags to see if actions bar should show buttons for a single task or a pair of
// tasks.
- mActionsView.updateForGroupedTask(isCurrentSplit);
+ boolean canSaveAppPair = isCurrentSplit && supportsAppPairs() &&
+ getSplitSelectController().getAppPairsController().canSaveAppPair(groupedTaskView);
+ mActionsView.updateForGroupedTask(isCurrentSplit, canSaveAppPair);
- boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
+ boolean isCurrentDesktop = taskView instanceof DesktopTaskView;
mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
}
@@ -4251,13 +4297,10 @@
alpha = Utilities.boundToRange(alpha, 0, 1);
mContentAlpha = alpha;
- int runningTaskId = getTaskIdsForRunningTaskView()[0];
+ TaskView runningTaskView = getRunningTaskView();
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
TaskView child = requireTaskViewAt(i);
- int[] childTaskIds = child.getTaskIds();
- if (runningTaskId != INVALID_TASK_ID
- && mRunningTaskTileHidden
- && (childTaskIds[0] == runningTaskId || childTaskIds[1] == runningTaskId)) {
+ if (runningTaskView != null && mRunningTaskTileHidden && child == runningTaskView) {
continue;
}
child.setStableAlpha(alpha);
@@ -4266,7 +4309,7 @@
int alphaInt = Math.round(alpha * 255);
mEmptyMessagePaint.setAlpha(alphaInt);
mEmptyIcon.setAlpha(alphaInt);
- mActionsView.getContentAlpha().setValue(mContentAlpha);
+ mActionsView.getContentAlpha().updateValue(mContentAlpha);
if (alpha > 0) {
setVisibility(VISIBLE);
@@ -4438,15 +4481,26 @@
setPivotY(mTempPointF.y);
}
+ /**
+ * Sets whether we should force-override the page offset mid-point to the current task, rather
+ * than the running task, when updating page offsets.
+ */
+ public void setOffsetMidpointIndexOverride(int offsetMidpointIndexOverride) {
+ mOffsetMidpointIndexOverride = offsetMidpointIndexOverride;
+ updatePageOffsets();
+ }
+
private void updatePageOffsets() {
float offset = mAdjacentPageHorizontalOffset;
float modalOffset = ACCELERATE_0_75.getInterpolation(mTaskModalness);
int count = getChildCount();
boolean showAsGrid = showAsGrid();
- TaskView runningTask = mRunningTaskViewId == -1 || !mRunningTaskTileHidden
+ TaskView runningTask = mRunningTaskViewId == INVALID_PAGE || !mRunningTaskTileHidden
? null : getRunningTaskView();
- int midpoint = runningTask == null ? -1 : indexOfChild(runningTask);
+ int midpoint = mOffsetMidpointIndexOverride == INVALID_PAGE
+ ? (runningTask == null ? INVALID_PAGE : indexOfChild(runningTask))
+ : mOffsetMidpointIndexOverride;
int modalMidpoint = getCurrentPage();
boolean isModalGridWithoutFocusedTask =
showAsGrid && enableGridOnlyOverview() && mTaskModalness > 0;
@@ -4690,7 +4744,7 @@
*/
public void resetModalVisuals() {
if (mSelectedTask != null) {
- mSelectedTask.getThumbnail().getTaskOverlay().resetModalVisuals();
+ mSelectedTask.getFirstThumbnailView().getTaskOverlay().resetModalVisuals();
}
}
@@ -4709,7 +4763,7 @@
StatsLogManager.EventEnum splitEvent) {
mSplitHiddenTaskView = taskView;
mSplitSelectStateController.setInitialTaskSelect(null /*intent*/,
- stagePosition, taskView.getItemInfo(), splitEvent, taskView.mTask.key.id);
+ stagePosition, taskView.getItemInfo(), splitEvent, taskView.getFirstTask().key.id);
mSplitSelectStateController.setAnimateCurrentTaskDismissal(
true /*animateCurrentTaskDismissal*/);
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
@@ -4731,7 +4785,7 @@
// Prevent dismissing whole task if we're only initiating from one of 2 tasks in split pair
mSplitSelectStateController.setDismissingFromSplitPair(mSplitHiddenTaskView != null
- && mSplitHiddenTaskView.containsMultipleTasks());
+ && mSplitHiddenTaskView instanceof GroupedTaskView);
mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
@@ -4752,19 +4806,19 @@
mSplitSelectStateController.isAnimateCurrentTaskDismissal();
boolean isInitiatingTaskViewSplitPair =
mSplitSelectStateController.isDismissingFromSplitPair();
- if (isInitiatingSplitFromTaskView && isInitiatingTaskViewSplitPair) {
+ if (isInitiatingSplitFromTaskView && isInitiatingTaskViewSplitPair
+ && mSplitHiddenTaskView instanceof GroupedTaskView) {
// Splitting from Overview for split pair task
createInitialSplitSelectAnimation(builder);
// Animate pair thumbnail into full thumbnail
- boolean primaryTaskSelected =
- mSplitHiddenTaskView.getTaskIdAttributeContainers()[0].getTask().key.id ==
- mSplitSelectStateController.getInitialTaskId();
- TaskIdAttributeContainer taskIdAttributeContainer = mSplitHiddenTaskView
- .getTaskIdAttributeContainers()[primaryTaskSelected ? 1 : 0];
- TaskThumbnailView thumbnail = taskIdAttributeContainer.getThumbnailView();
+ boolean primaryTaskSelected = mSplitHiddenTaskView.getTaskIds()[0]
+ == mSplitSelectStateController.getInitialTaskId();
+ TaskContainer taskContainer = mSplitHiddenTaskView
+ .getTaskContainers().get(primaryTaskSelected ? 1 : 0);
+ TaskThumbnailViewDeprecated thumbnail = taskContainer.getThumbnailView();
mSplitSelectStateController.getSplitAnimationController()
- .addInitialSplitFromPair(taskIdAttributeContainer, builder,
+ .addInitialSplitFromPair(taskContainer, builder,
mContainer.getDeviceProfile(),
mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(),
primaryTaskSelected);
@@ -5162,7 +5216,7 @@
updateGridProperties();
updateScrollSynchronously();
- int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+ int targetSysUiFlags = tv.getFirstThumbnailView().getSysUiStatusNavFlags();
final boolean[] passedOverviewThreshold = new boolean[] {false};
ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
progressAnim.addUpdateListener(animator -> {
@@ -5210,7 +5264,8 @@
mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
mPendingAnimation.addEndListener(isSuccess -> {
if (isSuccess) {
- if (tv.getTaskIds()[1] != -1 && mRemoteTargetHandles != null) {
+ if (tv instanceof GroupedTaskView && hasAllValidTaskIds(tv.getTaskIds())
+ && mRemoteTargetHandles != null) {
// TODO(b/194414938): make this part of the animations instead.
TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
mRemoteTargetHandles[0].getTransformParams().getTargetSet().nonApps,
@@ -5225,7 +5280,7 @@
} else {
tv.launchTask(this::onTaskLaunchAnimationEnd);
}
- Task task = tv.getTask();
+ Task task = tv.getFirstTask();
if (task != null) {
mContainer.getStatsLogManager().logger().withItemInfo(tv.getItemInfo())
.log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
@@ -5435,8 +5490,9 @@
* Called when a running recents animation has finished or canceled.
*/
public void onRecentsAnimationComplete() {
- Log.d(TAG, "onRecentsAnimationComplete - mRecentsAnimationController: "
- + mRecentsAnimationController);
+ Log.d(TAG, "onRecentsAnimationComplete "
+ + "- mRecentsAnimationController: " + mRecentsAnimationController
+ + ", mSideTaskLaunchCallback: " + mSideTaskLaunchCallback);
// At this point, the recents animation is not running and if the animation was canceled
// by a display rotation then reset this state to show the screenshot
setRunningTaskViewShowScreenshot(true);
@@ -5857,15 +5913,14 @@
}
taskView.setShowScreenshot(true);
- for (TaskIdAttributeContainer container :
- taskView.getTaskIdAttributeContainers()) {
+ for (TaskContainer container : taskView.getTaskContainers()) {
if (container == null) {
continue;
}
ThumbnailData td =
mRecentsAnimationController.screenshotTask(container.getTask().key.id);
- TaskThumbnailView thumbnailView = container.getThumbnailView();
+ TaskThumbnailViewDeprecated thumbnailView = container.getThumbnailView();
if (td != null) {
thumbnailView.setThumbnail(container.getTask(), td);
} else {
@@ -5990,7 +6045,8 @@
}
public void cleanupRemoteTargets() {
- Log.d(TAG, "cleanupRemoteTargets");
+ Log.d(TAG, "cleanupRemoteTargets - mRemoteTargetHandles: " + Arrays.toString(
+ mRemoteTargetHandles));
mRemoteTargetHandles = null;
}
@@ -6227,7 +6283,7 @@
/**
* Moves the provided task into desktop mode, and invoke {@code successCallback} if succeeded.
*/
- public void moveTaskToDesktop(TaskIdAttributeContainer taskContainer,
+ public void moveTaskToDesktop(TaskContainer taskContainer,
Runnable successCallback) {
if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
return;
@@ -6236,7 +6292,7 @@
() -> moveTaskToDesktopInternal(taskContainer, successCallback)));
}
- private void moveTaskToDesktopInternal(TaskIdAttributeContainer taskContainer,
+ private void moveTaskToDesktopInternal(TaskContainer taskContainer,
Runnable successCallback) {
if (mDesktopRecentsTransitionController == null) {
return;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index fcbb45b..578d471 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -18,11 +18,9 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
-import static com.android.launcher3.testing.shared.TestProtocol.TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
+import static com.android.quickstep.views.TaskThumbnailViewDeprecated.DIM_ALPHA;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -56,7 +54,7 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.TaskCornerRadius;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
/**
* Contains options for a recent task when long-pressing its icon.
@@ -76,7 +74,7 @@
private ValueAnimator mRevealAnimator;
@Nullable private Runnable mOnClosingStartCallback;
private TaskView mTaskView;
- private TaskIdAttributeContainer mTaskContainer;
+ private TaskContainer mTaskContainer;
private LinearLayout mOptionLayout;
private float mMenuTranslationYBeforeOpen;
private float mMenuTranslationXBeforeOpen;
@@ -163,7 +161,10 @@
}
}
- public static boolean showForTask(TaskIdAttributeContainer taskContainer,
+ /**
+ * Show a task menu for the given taskContainer.
+ */
+ public static boolean showForTask(TaskContainer taskContainer,
@Nullable Runnable onClosingStartCallback) {
RecentsViewContainer container = RecentsViewContainer.containerFromContext(
taskContainer.getTaskView().getContext());
@@ -173,11 +174,14 @@
return taskMenuView.populateAndShowForTask(taskContainer);
}
- public static boolean showForTask(TaskIdAttributeContainer taskContainer) {
+ /**
+ * Show a task menu for the given taskContainer.
+ */
+ public static boolean showForTask(TaskContainer taskContainer) {
return showForTask(taskContainer, null);
}
- private boolean populateAndShowForTask(TaskIdAttributeContainer taskContainer) {
+ private boolean populateAndShowForTask(TaskContainer taskContainer) {
if (isAttachedToWindow()) {
return false;
}
@@ -193,16 +197,12 @@
/** @return true if successfully able to populate task view menu, false otherwise */
private boolean populateAndLayoutMenu() {
- if (mTaskContainer.getTask().icon == null) {
- // Icon may not be loaded
- return false;
- }
addMenuOptions(mTaskContainer);
orientAroundTaskView(mTaskContainer);
return true;
}
- private void addMenuOptions(TaskIdAttributeContainer taskContainer) {
+ private void addMenuOptions(TaskContainer taskContainer) {
if (enableOverviewIconMenu()) {
removeView(mTaskName);
} else {
@@ -230,7 +230,7 @@
mOptionLayout.addView(menuOptionView);
}
- private void orientAroundTaskView(TaskIdAttributeContainer taskContainer) {
+ private void orientAroundTaskView(TaskContainer taskContainer) {
RecentsView recentsView = mContainer.getOverviewPanel();
RecentsPagedOrientationHandler orientationHandler =
recentsView.getPagedOrientationHandler();
@@ -305,7 +305,6 @@
private void animateOpenOrClosed(boolean closing) {
if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
- testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "getting canceled");
mOpenCloseAnimator.cancel();
}
mOpenCloseAnimator = new AnimatorSet();
@@ -362,14 +361,10 @@
iconAppChip.getMenuTranslationX(),
MULTI_PROPERTY_VALUE, closing ? 0 : -additionalTranslationX);
menuTranslationXAnim.setInterpolator(EMPHASIZED);
- testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
- "TaskMenuView.java.animateOpenOrClosed: running translation animations");
mOpenCloseAnimator.playTogether(translationYAnim, translationXAnim,
menuTranslationXAnim, menuTranslationYAnim);
}
- testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
- "TaskMenuView.java.animateOpenOrClosed: running animation 2");
mOpenCloseAnimator.playTogether(mRevealAnimator,
ObjectAnimator.ofFloat(
mTaskContainer.getThumbnailView(), DIM_ALPHA,
@@ -378,8 +373,6 @@
mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
- testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
- "TaskMenuView.java.animateOpenOrClosed: onAnimationStart");
setVisibility(VISIBLE);
if (closing && mOnClosingStartCallback != null) {
mOnClosingStartCallback.run();
@@ -387,16 +380,7 @@
}
@Override
- public void onAnimationCancel(Animator animation) {
- super.onAnimationCancel(animation);
- testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
- "TaskMenuView.java.animateOpenOrClosed: onAnimationCancel");
- }
-
- @Override
public void onAnimationSuccess(Animator animator) {
- testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
- "TaskMenuView.java.animateOpenOrClosed: onAnimationSuccess");
if (closing) {
closeComplete();
}
@@ -407,7 +391,6 @@
}
private void closeComplete() {
- testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "TaskMenuView.java.closeComplete");
mIsOpen = false;
mContainer.getDragLayer().removeView(this);
mRevealAnimator = null;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index c124f03..7adc32e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -37,14 +37,14 @@
import com.android.launcher3.popup.SystemShortcut
import com.android.launcher3.util.Themes
import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
class TaskMenuViewWithArrow<T> : ArrowPopup<T> where T : RecentsViewContainer, T : Context {
companion object {
const val TAG = "TaskMenuViewWithArrow"
fun <T> showForTask(
- taskContainer: TaskIdAttributeContainer,
+ taskContainer: TaskContainer,
alignedOptionIndex: Int = 0
): Boolean where T : RecentsViewContainer, T : Context {
val container: RecentsViewContainer =
@@ -83,11 +83,11 @@
private var alignedOptionIndex: Int = 0
private val extraSpaceForRowAlignment: Int
get() = optionMeasuredHeight * alignedOptionIndex
- private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid)
+ private val menuPaddingEnd = context.resources.getDimensionPixelSize(R.dimen.task_card_margin)
private lateinit var taskView: TaskView
private lateinit var optionLayout: LinearLayout
- private lateinit var taskContainer: TaskIdAttributeContainer
+ private lateinit var taskContainer: TaskContainer
private var optionMeasuredHeight = 0
private val arrowHorizontalPadding: Int
@@ -141,7 +141,7 @@
}
private fun populateAndShowForTask(
- taskContainer: TaskIdAttributeContainer,
+ taskContainer: TaskContainer,
alignedOptionIndex: Int
): Boolean {
if (isAttachedToWindow) {
@@ -174,10 +174,10 @@
/** @return true if successfully able to populate task view menu, false otherwise */
private fun populateMenu(): Boolean {
// Icon may not be loaded
- if (taskContainer.task.icon == null) return false
+ if (taskContainer.iconView.drawable == null) return false
addMenuOptions()
- return true
+ return optionLayout.childCount > 0
}
private fun addMenuOptions() {
@@ -213,7 +213,13 @@
menuOptionView.requireViewById(R.id.text)
)
val lp = menuOptionView.layoutParams as LayoutParams
- lp.width = menuWidth
+ lp.width = LayoutParams.MATCH_PARENT
+ menuOptionView.setPaddingRelative(
+ menuOptionView.paddingStart,
+ menuOptionView.paddingTop,
+ menuPaddingEnd,
+ menuOptionView.paddingBottom
+ )
menuOptionView.setOnClickListener { view: View? -> menuOption.onClick(view) }
optionLayout.addView(menuOptionView)
}
@@ -347,7 +353,7 @@
override fun updateArrowColor() {
mArrow.background =
- RoundedArrowDrawable(
+ RoundedArrowDrawable.createHorizontalRoundedArrow(
mArrowWidth.toFloat(),
mArrowHeight.toFloat(),
mArrowPointRadius.toFloat(),
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
similarity index 91%
rename from quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
rename to quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
index 7e46739..21c6ca8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
@@ -53,6 +53,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
+import com.android.launcher3.util.ViewPool;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
@@ -62,61 +63,66 @@
/**
* A task in the Recents view.
+ *
+ * @deprecated This class will be replaced by the new [TaskThumbnailView].
*/
-public class TaskThumbnailView extends View {
+@Deprecated
+public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusable {
private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
new MainThreadInitializedObject<>(FullscreenDrawParams::new);
- public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
- new FloatProperty<TaskThumbnailView>("dimAlpha") {
+ public static final Property<TaskThumbnailViewDeprecated, Float> DIM_ALPHA =
+ new FloatProperty<TaskThumbnailViewDeprecated>("dimAlpha") {
@Override
- public void setValue(TaskThumbnailView thumbnail, float dimAlpha) {
+ public void setValue(TaskThumbnailViewDeprecated thumbnail, float dimAlpha) {
thumbnail.setDimAlpha(dimAlpha);
}
@Override
- public Float get(TaskThumbnailView thumbnailView) {
+ public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mDimAlpha;
}
};
- public static final Property<TaskThumbnailView, Float> SPLASH_ALPHA =
- new FloatProperty<TaskThumbnailView>("splashAlpha") {
+ public static final Property<TaskThumbnailViewDeprecated, Float> SPLASH_ALPHA =
+ new FloatProperty<TaskThumbnailViewDeprecated>("splashAlpha") {
@Override
- public void setValue(TaskThumbnailView thumbnail, float splashAlpha) {
+ public void setValue(TaskThumbnailViewDeprecated thumbnail, float splashAlpha) {
thumbnail.setSplashAlpha(splashAlpha);
}
@Override
- public Float get(TaskThumbnailView thumbnailView) {
+ public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mSplashAlpha / 255f;
}
};
/** Use to animate thumbnail translationX while first app in split selection is initiated */
- public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_X =
- new FloatProperty<TaskThumbnailView>("splitSelectTranslateX") {
+ public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_X =
+ new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateX") {
@Override
- public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateX) {
+ public void setValue(TaskThumbnailViewDeprecated thumbnail,
+ float splitSelectTranslateX) {
thumbnail.applySplitSelectTranslateX(splitSelectTranslateX);
}
@Override
- public Float get(TaskThumbnailView thumbnailView) {
+ public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mSplitSelectTranslateX;
}
};
/** Use to animate thumbnail translationY while first app in split selection is initiated */
- public static final Property<TaskThumbnailView, Float> SPLIT_SELECT_TRANSLATE_Y =
- new FloatProperty<TaskThumbnailView>("splitSelectTranslateY") {
+ public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_Y =
+ new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateY") {
@Override
- public void setValue(TaskThumbnailView thumbnail, float splitSelectTranslateY) {
+ public void setValue(TaskThumbnailViewDeprecated thumbnail,
+ float splitSelectTranslateY) {
thumbnail.applySplitSelectTranslateY(splitSelectTranslateY);
}
@Override
- public Float get(TaskThumbnailView thumbnailView) {
+ public Float get(TaskThumbnailViewDeprecated thumbnailView) {
return thumbnailView.mSplitSelectTranslateY;
}
};
@@ -156,15 +162,16 @@
private float mSplitSelectTranslateX;
private float mSplitSelectTranslateY;
- public TaskThumbnailView(Context context) {
+ public TaskThumbnailViewDeprecated(Context context) {
this(context, null);
}
- public TaskThumbnailView(Context context, @Nullable AttributeSet attrs) {
+ public TaskThumbnailViewDeprecated(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public TaskThumbnailView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ public TaskThumbnailViewDeprecated(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint.setFilterBitmap(true);
mBackgroundPaint.setColor(Color.WHITE);
@@ -180,7 +187,6 @@
/**
* Updates the thumbnail to draw the provided task
- * @param task
*/
public void bind(Task task) {
getTaskOverlay().reset();
@@ -194,6 +200,7 @@
/**
* Updates the thumbnail.
+ *
* @param refreshNow whether the {@code thumbnailData} will be used to redraw immediately.
* In most cases, we use the {@link #setThumbnail(Task, ThumbnailData)}
* version with {@code refreshNow} is true. The only exception is
@@ -227,6 +234,7 @@
/**
* Updates the shader, paint, matrix to redraw.
+ *
* @param shouldRefreshOverlay whether to re-initialize overlay
*/
private void refresh(boolean shouldRefreshOverlay) {
@@ -253,7 +261,6 @@
* <p>
* If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
* extracted background color.
- *
*/
public void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
@@ -286,6 +293,7 @@
/**
* Get the scaled insets that are being used to draw the task view. This is a subsection of
* the full snapshot.
+ *
* @return the insets in snapshot bitmap coordinates.
*/
@RequiresApi(api = Build.VERSION_CODES.Q)
@@ -599,4 +607,9 @@
}
return mThumbnailData.isRealSnapshot && !mTask.isLocked;
}
+
+ @Override
+ public void onRecycle() {
+ // Do nothing
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ec57115..cc24bc3 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -16,7 +16,6 @@
package com.android.quickstep.views;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.widget.Toast.LENGTH_SHORT;
@@ -25,13 +24,12 @@
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
+import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
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.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -49,7 +47,6 @@
import android.animation.ObjectAnimator;
import android.annotation.IdRes;
import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
@@ -93,6 +90,7 @@
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.TraceHelper;
@@ -107,6 +105,9 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.task.thumbnail.TaskThumbnail;
+import com.android.quickstep.task.thumbnail.TaskThumbnailView;
+import com.android.quickstep.task.viewmodel.TaskViewData;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.BorderAnimator;
import com.android.quickstep.util.RecentsOrientedState;
@@ -118,22 +119,24 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import kotlin.Unit;
+
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Stream;
-import kotlin.Unit;
/**
* A task in the Recents view.
*/
public class TaskView extends FrameLayout implements Reusable {
- private static final String TAG = TaskView.class.getSimpleName();
+ private static final String TAG = "TaskView";
public static final int FLAG_UPDATE_ICON = 1;
public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
public static final int FLAG_UPDATE_CORNER_RADIUS = FLAG_UPDATE_THUMBNAIL << 1;
@@ -147,7 +150,8 @@
*/
@Retention(SOURCE)
@IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL, FLAG_UPDATE_CORNER_RADIUS})
- public @interface TaskDataChanges {}
+ public @interface TaskDataChanges {
+ }
/**
* Type of task view
@@ -319,13 +323,13 @@
@Override
public Float get(TaskView taskView) {
- return taskView.mSnapshotView.getScaleX();
+ return taskView.mTaskThumbnailViewDeprecated.getScaleX();
}
};
- @Nullable
- protected Task mTask;
- protected TaskThumbnailView mSnapshotView;
+ public TaskViewData mTaskViewData = new TaskViewData();
+ protected TaskThumbnailViewDeprecated mTaskThumbnailViewDeprecated;
+ protected TaskThumbnailView mTaskThumbnailView;
protected TaskViewIcon mIconView;
protected final DigitalWellBeingToast mDigitalWellBeingToast;
protected float mFullscreenProgress;
@@ -366,12 +370,7 @@
private float mStableAlpha = 1;
private int mTaskViewId = -1;
- /**
- * Index 0 will contain taskID of left/top task, index 1 will contain taskId of bottom/right
- */
- protected int[] mTaskIdContainer = new int[]{-1, -1};
- protected TaskIdAttributeContainer[] mTaskIdAttributeContainer =
- new TaskIdAttributeContainer[2];
+ protected List<TaskContainer> mTaskContainers = Collections.emptyList();
private boolean mShowScreenshot;
private boolean mBorderEnabled;
@@ -390,9 +389,11 @@
private boolean mIsClickableAsLiveTile = true;
- @Nullable private final BorderAnimator mFocusBorderAnimator;
+ @Nullable
+ private final BorderAnimator mFocusBorderAnimator;
- @Nullable private final BorderAnimator mHoverBorderAnimator;
+ @Nullable
+ private final BorderAnimator mHoverBorderAnimator;
public TaskView(Context context) {
this(context, null);
@@ -439,7 +440,7 @@
/* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
/* borderWidthPx= */ context.getResources().getDimensionPixelSize(
R.dimen.keyboard_quick_switch_border_width),
- /* boundsBuilder= */ this::updateBorderBounds,
+ /* boundsBuilder= */ this::getThumbnailBounds,
/* targetView= */ this,
/* borderColor= */ styledAttrs.getColor(
R.styleable.TaskView_focusBorderColor, DEFAULT_BORDER_COLOR))
@@ -454,7 +455,7 @@
/* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
/* borderWidthPx= */ context.getResources().getDimensionPixelSize(
R.dimen.task_hover_border_width),
- /* boundsBuilder= */ this::updateBorderBounds,
+ /* boundsBuilder= */ this::getThumbnailBounds,
/* targetView= */ this,
/* borderColor= */ styledAttrs.getColor(
R.styleable.TaskView_hoverBorderColor, DEFAULT_BORDER_COLOR))
@@ -463,11 +464,23 @@
styledAttrs.recycle();
}
- protected Unit updateBorderBounds(@NonNull Rect bounds) {
- bounds.set(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
- mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
- mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
- mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()));
+ /** Returns the thumbnail's bounds relative to this view. */
+ public Unit getThumbnailBounds(@NonNull Rect bounds) {
+ return getThumbnailBounds(bounds, false);
+ }
+
+ /** Returns the thumbnail's bounds, optionally relative to the screen. */
+ public Unit getThumbnailBounds(@NonNull Rect bounds, boolean relativeToDragLayer) {
+ View snapshotView = getSnapshotView();
+
+ if (relativeToDragLayer) {
+ mContainer.getDragLayer().getDescendantRectRelativeToSelf(snapshotView, bounds);
+ } else {
+ bounds.set(snapshotView.getLeft() + Math.round(snapshotView.getTranslationX()),
+ snapshotView.getTop() + Math.round(snapshotView.getTranslationY()),
+ snapshotView.getRight() + Math.round(snapshotView.getTranslationX()),
+ snapshotView.getBottom() + Math.round(snapshotView.getTranslationY()));
+ }
return Unit.INSTANCE;
}
@@ -480,10 +493,24 @@
}
/**
- * Builds proto for logging
+ * Updates [TaskThumbnailView] to reflect the latest [Task] state (i.e., task isRunning).
*/
+ public void notifyIsRunningTaskUpdated() {
+ // TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
+ // so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
+ if (!mTaskContainers.isEmpty()) {
+ bindTaskThumbnailView();
+ }
+ }
+
+ /**
+ * Builds proto for logging.
+ *
+ * @deprecated Use {@link #getItemInfo(Task)} instead.
+ */
+ @Deprecated
public WorkspaceItemInfo getItemInfo() {
- return getItemInfo(mTask);
+ return getItemInfo(getFirstTask());
}
/**
@@ -516,7 +543,14 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mSnapshotView = findViewById(R.id.snapshot);
+ mTaskThumbnailViewDeprecated = findViewById(R.id.snapshot);
+ if (enableRefactorTaskThumbnail()) {
+ mTaskThumbnailView = new TaskThumbnailView(mContext);
+ mTaskThumbnailView.setLayoutParams(mTaskThumbnailViewDeprecated.getLayoutParams());
+ int indexOfSnapshotView = indexOfChild(mTaskThumbnailViewDeprecated);
+ addView(mTaskThumbnailView, indexOfSnapshotView);
+ mTaskThumbnailViewDeprecated.setVisibility(View.GONE);
+ }
ViewStub iconViewStub = findViewById(R.id.icon);
if (enableOverviewIconMenu()) {
iconViewStub.setLayoutResource(R.layout.icon_app_chip_view);
@@ -559,6 +593,10 @@
* Enable or disable showing border on hover and focus change
*/
public void setBorderEnabled(boolean enabled) {
+ if (mBorderEnabled == enabled) {
+ return;
+ }
+
mBorderEnabled = enabled;
// Set the animation correctly in case it misses the hover/focus event during state
// transition
@@ -649,20 +687,35 @@
*/
public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks();
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.bind: task=" + task);
- mTask = task;
- mTaskIdContainer[0] = mTask.key.id;
- mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView, mIconView,
- STAGE_POSITION_UNDEFINED);
- mSnapshotView.bind(task);
+ setupTaskContainers(task);
setOrientationState(orientedState);
}
+ protected void setupTaskContainers(Task task) {
+ mTaskContainers = Collections.singletonList(
+ new TaskContainer(task, mTaskThumbnailViewDeprecated, mIconView,
+ STAGE_POSITION_UNDEFINED, mDigitalWellBeingToast));
+ if (enableRefactorTaskThumbnail()) {
+ bindTaskThumbnailView();
+ } else {
+ mTaskThumbnailViewDeprecated.bind(task);
+ }
+ }
+
+ private void bindTaskThumbnailView() {
+ // TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
+ // so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
+ mTaskThumbnailView.getViewModel().bind(new TaskThumbnail(getFirstTask(), isRunningTask()));
+ }
+
/**
* Sets up an on-click listener and the visibility for show_windows icon on top of the task.
*/
public void setUpShowAllInstancesListener() {
- String taskPackageName = mTaskIdAttributeContainer[0].mTask.key.getPackageName();
+ if (mTaskContainers.isEmpty()) {
+ return;
+ }
+ String taskPackageName = mTaskContainers.get(0).getTask().key.getPackageName();
// icon of the top/left task
View showWindowsView = findViewById(R.id.show_windows);
@@ -704,78 +757,101 @@
filterView.setOnClickListener(callback);
}
- public TaskIdAttributeContainer[] getTaskIdAttributeContainers() {
- return mTaskIdAttributeContainer;
+ /**
+ * Returns a list of all TaskContainers in the TaskView.
+ */
+ public List<TaskContainer> getTaskContainers() {
+ return mTaskContainers;
}
+ /**
+ * Returns the first task bound to this TaskView.
+ *
+ * @deprecated Use {@link #mTaskContainers} instead.
+ */
+ @Deprecated
@Nullable
- public Task getTask() {
- return mTask;
+ public Task getFirstTask() {
+ return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getTask() : null;
}
/**
* Check if given {@code taskId} is tracked in this view
*/
public boolean containsTaskId(int taskId) {
- return mTask != null && mTask.key.id == taskId;
+ return getTaskContainerById(taskId) != null;
}
/**
- * @return integer array of two elements to be size consistent with max number of tasks possible
- * index 0 will contain the taskId, index 1 will be -1 indicating a null taskID value
+ * Returns a copy of integer array containing taskIds of all tasks in the TaskView.
*/
public int[] getTaskIds() {
- return Arrays.copyOf(mTaskIdContainer, mTaskIdContainer.length);
+ return mTaskContainers.stream().mapToInt(
+ container -> container.getTask().key.id).toArray();
}
public boolean containsMultipleTasks() {
- return mTaskIdContainer[1] != -1;
+ return mTaskContainers.size() > 1;
}
/**
- * Returns the TaskIdAttributeContainer corresponding to a given taskId, or null if the TaskView
- * does not contain a Task with that ID.
+ * Returns the TaskContainer corresponding to a given taskId, or null if the TaskView does
+ * not contain a Task with that ID.
*/
@Nullable
- public TaskIdAttributeContainer getTaskAttributesById(int taskId) {
- for (TaskIdAttributeContainer attributes : mTaskIdAttributeContainer) {
- if (attributes.getTask().key.id == taskId) {
- return attributes;
- }
- }
-
- return null;
+ public TaskContainer getTaskContainerById(int taskId) {
+ return mTaskContainers.stream().filter(
+ container -> container.getTask().key.id == taskId).findFirst().orElse(null);
}
- public TaskThumbnailView getThumbnail() {
- return mSnapshotView;
+ /**
+ * Returns the first thumbnailView of the TaskView.
+ *
+ * @deprecated Use {@link #mTaskContainers} instead.
+ */
+ @Deprecated
+ public TaskThumbnailViewDeprecated getFirstThumbnailView() {
+ return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getThumbnailView()
+ : mTaskThumbnailViewDeprecated;
}
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
- if (mTask != null && thumbnailDatas != null) {
- final ThumbnailData thumbnailData = thumbnailDatas.get(mTask.key.id);
+ if (enableRefactorTaskThumbnail()) {
+ // TODO(b/334825222) add thumbnail logic
+ return;
+ }
+ if (getFirstTask() != null && thumbnailDatas != null) {
+ final ThumbnailData thumbnailData = thumbnailDatas.get(getFirstTask().key.id);
if (thumbnailData != null) {
- mSnapshotView.setThumbnail(mTask, thumbnailData);
+ mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(), thumbnailData);
return;
}
}
- mSnapshotView.refresh();
+ mTaskThumbnailViewDeprecated.refresh();
}
- /** TODO(b/197033698) Remove all usages of above method and migrate to this one */
- public TaskThumbnailView[] getThumbnails() {
- return new TaskThumbnailView[]{mSnapshotView};
+ public TaskThumbnailViewDeprecated[] getThumbnailViews() {
+ return mTaskContainers.stream().map(
+ TaskContainer::getThumbnailView).toArray(
+ TaskThumbnailViewDeprecated[]::new);
}
- public TaskViewIcon getIconView() {
- return mIconView;
+ /**
+ * Returns the first iconView of the TaskView.
+ *
+ * @deprecated Use {@link #mTaskContainers} instead.
+ */
+ @Deprecated
+ @Nullable
+ public TaskViewIcon getFirstIconView() {
+ return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getIconView() : null;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
RecentsView recentsView = getRecentsView();
- if (recentsView == null || getTask() == null) {
+ if (recentsView == null || getFirstTask() == null) {
return false;
}
SplitSelectStateController splitSelectStateController =
@@ -783,7 +859,7 @@
// Disable taps for split selection animation unless we have multiple tasks
boolean disableTapsForSplitSelect =
splitSelectStateController.isSplitSelectActive()
- && splitSelectStateController.getInitialTaskId() == getTask().key.id
+ && splitSelectStateController.getInitialTaskId() == getFirstTask().key.id
&& !containsMultipleTasks();
if (disableTapsForSplitSelect) {
return false;
@@ -795,38 +871,22 @@
return super.dispatchTouchEvent(ev);
}
- /**
- * @return taskId that split selection was initiated with,
- * {@link ActivityTaskManager#INVALID_TASK_ID} if no tasks in this TaskView are part of
- * split selection
- */
- protected int getThisTaskCurrentlyInSplitSelection() {
- SplitSelectStateController splitSelectController =
- getRecentsView().getSplitSelectController();
- int initSplitTaskId = INVALID_TASK_ID;
- for (TaskIdAttributeContainer container : getTaskIdAttributeContainers()) {
- int taskId = container.getTask().key.id;
- if (taskId == splitSelectController.getInitialTaskId()) {
- initSplitTaskId = taskId;
- break;
- }
- }
- return initSplitTaskId;
- }
-
private void onClick(View view) {
- if (getTask() == null) {
+ if (getFirstTask() == null) {
Log.d("b/310064698", "onClick - task is null");
return;
}
if (confirmSecondSplitSelectApp()) {
- Log.d("b/310064698", mTask + " - onClick - split select is active");
+ Log.d("b/310064698",
+ Arrays.toString(getTaskIds()) + " - onClick - split select is active");
return;
}
RunnableList callbackList = launchTasks();
- Log.d("b/310064698", mTask + " - onClick - callbackList: " + callbackList);
+ Log.d("b/310064698",
+ Arrays.toString(getTaskIds()) + " - onClick - callbackList: " + callbackList);
if (callbackList != null) {
- callbackList.add(() -> Log.d("b/310064698", mTask + " - onClick - launchCompleted"));
+ callbackList.add(() -> Log.d("b/310064698",
+ Arrays.toString(getTaskIds()) + " - onClick - launchCompleted"));
}
mContainer.getStatsLogManager().logger().withItemInfo(getItemInfo())
.log(LAUNCHER_TASK_LAUNCH_TAP);
@@ -834,11 +894,14 @@
/**
* @return {@code true} if user is already in split select mode and this tap was to choose the
- * second app. {@code false} otherwise
+ * second app. {@code false} otherwise
*/
protected boolean confirmSecondSplitSelectApp() {
int index = getLastSelectedChildTaskIndex();
- TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
+ if (index >= mTaskContainers.size()) {
+ return false;
+ }
+ TaskContainer container = mTaskContainers.get(index);
if (container != null) {
return getRecentsView().confirmSplitSelect(this, container.getTask(),
container.getIconView().getDrawable(), container.getThumbnailView(),
@@ -859,22 +922,22 @@
/**
* Starts the task associated with this view and animates the startup.
+ *
* @return CompletionStage to indicate the animation completion or null if the launch failed.
*/
@Nullable
public RunnableList launchTaskAnimated() {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTaskAnimated: mTask=" + mTask);
- if (mTask != null) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTaskAnimated: startActivityFromRecentsAsync");
+ if (getFirstTask() != null) {
TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
- ActivityOptionsWrapper opts = mContainer.getActivityLaunchOptions(this, null);
+ TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", Arrays.toString(
+ getTaskIds()));
+ ActivityOptionsWrapper opts = mContainer.getActivityLaunchOptions(this, null);
opts.options.setLaunchDisplayId(
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (ActivityManagerWrapper.getInstance()
- .startActivityFromRecents(mTask.key, opts.options)) {
+ .startActivityFromRecents(getFirstTask().key, opts.options)) {
+ Log.d(TAG, "launchTaskAnimated - startActivityFromRecents: " + Arrays.toString(
+ getTaskIds()));
ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
RecentsView recentsView = getRecentsView();
if (recentsView.getRunningTaskViewId() != -1) {
@@ -900,6 +963,7 @@
return null;
}
} else {
+ Log.d(TAG, "launchTaskAnimated - getTask() is null" + Arrays.toString(getTaskIds()));
return null;
}
}
@@ -915,20 +979,18 @@
* Starts the task associated with this view without any animation
*/
public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTask: mTask=" + mTask);
- if (mTask != null) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTask: startActivityFromRecentsAsync");
+ if (getFirstTask() != null) {
TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
+ TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", Arrays.toString(
+ getTaskIds()));
- final TaskRemovedDuringLaunchListener
- failureListener = new TaskRemovedDuringLaunchListener();
+ TaskRemovedDuringLaunchListener failureListener = new TaskRemovedDuringLaunchListener(
+ getContext().getApplicationContext());
if (isQuickswitch) {
// We only listen for failures to launch in quickswitch because the during this
// gesture launcher is in the background state, vs other launches which are in
// the actual overview state
- failureListener.register(mContainer, mTask.key.id, () -> {
+ failureListener.register(mContainer, getFirstTask().key.id, () -> {
notifyTaskLaunchFailed(TAG);
RecentsView rv = getRecentsView();
if (rv != null) {
@@ -950,19 +1012,18 @@
// Indicate success once the system has indicated that the transition has started
ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
MAIN_EXECUTOR.getHandler(),
- elapsedRealTime -> {
- callback.accept(true);
- },
- elapsedRealTime -> {
- failureListener.onTransitionFinished();
- });
+ elapsedRealTime -> callback.accept(true),
+ elapsedRealTime -> failureListener.onTransitionFinished());
opts.setLaunchDisplayId(
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (isQuickswitch) {
opts.setFreezeRecentTasksReordering();
}
- opts.setDisableStartingWindow(mSnapshotView.shouldShowSplashView());
- Task.TaskKey key = mTask.key;
+ // TODO(b/334826842) add splash functionality to new TTV
+ if (!enableRefactorTaskThumbnail()) {
+ opts.setDisableStartingWindow(mTaskThumbnailViewDeprecated.shouldShowSplashView());
+ }
+ Task.TaskKey key = getFirstTask().key;
UI_HELPER_EXECUTOR.execute(() -> {
if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
// If the call to start activity failed, then post the result immediately,
@@ -973,9 +1034,12 @@
callback.accept(false);
});
}
+ Log.d(TAG,
+ "launchTask - startActivityFromRecents: " + Arrays.toString(getTaskIds()));
});
} else {
callback.accept(false);
+ Log.d(TAG, "launchTask - getTask() is null" + Arrays.toString(getTaskIds()));
}
}
@@ -986,9 +1050,6 @@
public RunnableList launchTasks() {
RecentsView recentsView = getRecentsView();
RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTasks: isRunningTask=" + isRunningTask() + ", "
- + "remoteTargetHandles == null?" + (remoteTargetHandles == null));
if (isRunningTask() && remoteTargetHandles != null) {
if (!mIsClickableAsLiveTile) {
Log.e(TAG, "TaskView is not clickable as a live tile; returning to home.");
@@ -1015,8 +1076,6 @@
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.
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTasks: recents animation is cancelled");
RunnableList runnableList = launchTaskAnimated();
if (runnableList == null) {
Log.e(TAG, "Recents animation cancelled and cannot launch task as non-live tile"
@@ -1036,9 +1095,8 @@
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
- if (mTask != null && mTask.key.displayId != getRootViewDisplayId()) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTasks: onAnimationEnd");
+ if (getFirstTask() != null
+ && getFirstTask().key.displayId != getRootViewDisplayId()) {
launchTaskAnimated();
}
mIsClickableAsLiveTile = true;
@@ -1055,6 +1113,8 @@
}
});
anim.start();
+ Log.d(TAG, "launchTasks - composeRecentsLaunchAnimator: " + Arrays.toString(
+ getTaskIds()));
recentsView.onTaskLaunchedInLiveTileMode();
return runnableList;
} else {
@@ -1064,6 +1124,7 @@
/**
* See {@link TaskDataChanges}
+ *
* @param visible If this task view will be visible to the user in overview or hidden
*/
public void onTaskListVisibilityChanged(boolean visible) {
@@ -1072,10 +1133,11 @@
/**
* See {@link TaskDataChanges}
+ *
* @param visible If this task view will be visible to the user in overview or hidden
*/
public void onTaskListVisibilityChanged(boolean visible, @TaskDataChanges int changes) {
- if (mTask == null) {
+ if (getFirstTask() == null) {
return;
}
cancelPendingLoadTasks();
@@ -1088,12 +1150,16 @@
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
- mTask, thumbnail -> {
- mSnapshotView.setThumbnail(mTask, thumbnail);
+ getFirstTask(), thumbnail -> {
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334825222) add thumbnail state
+ mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(),
+ thumbnail);
+ }
});
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
- mIconLoadRequest = iconCache.updateIconInBackground(mTask,
+ mIconLoadRequest = iconCache.updateIconInBackground(getFirstTask(),
(task) -> {
setIcon(mIconView, task.icon);
if (enableOverviewIconMenu()) {
@@ -1107,10 +1173,13 @@
}
} else {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- mSnapshotView.setThumbnail(null, null);
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334825222) add thumbnail state
+ mTaskThumbnailViewDeprecated.setThumbnail(null, null);
+ }
// Reset the task thumbnail reference as well (it will be fetched from the cache or
// reloaded next time we need it)
- mTask.thumbnail = null;
+ getFirstTask().thumbnail = null;
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
setIcon(mIconView, null);
@@ -1154,29 +1223,33 @@
}
protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
- TaskIdAttributeContainer menuContainer =
- mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1];
+ Optional<TaskContainer> menuContainer = mTaskContainers.stream().filter(
+ container -> container.getIconView() == iconView).findAny();
+ if (menuContainer.isEmpty()) {
+ return false;
+ }
DeviceProfile dp = mContainer.getDeviceProfile();
if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) {
((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true);
- return TaskMenuView.showForTask(menuContainer,
+ return TaskMenuView.showForTask(menuContainer.get(),
() -> ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false));
} else if (dp.isTablet) {
int alignedOptionIndex = 0;
- if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) {
+ if (getRecentsView().isOnGridBottomRow(menuContainer.get().getTaskView())
+ && dp.isLandscape) {
if (Flags.enableGridOnlyOverview()) {
// With no focused task, there is less available space below the tasks, so align
// the arrow to the third option in the menu.
alignedOptionIndex = 2;
- } else {
+ } else {
// Bottom row of landscape grid aligns arrow to second option to avoid clipping
alignedOptionIndex = 1;
}
}
- return TaskMenuViewWithArrow.Companion.showForTask(menuContainer,
+ return TaskMenuViewWithArrow.Companion.showForTask(menuContainer.get(),
alignedOptionIndex);
} else {
- return TaskMenuView.showForTask(menuContainer);
+ return TaskMenuView.showForTask(menuContainer.get());
}
}
@@ -1215,12 +1288,16 @@
// TODO(b/271468547), we should default to setting trasnlations only on the snapshot instead
// of a hybrid of both margins and translations
- LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
+ LayoutParams snapshotParams = (LayoutParams) getSnapshotView().getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
- mSnapshotView.setLayoutParams(snapshotParams);
+ getSnapshotView().setLayoutParams(snapshotParams);
- mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
- mDigitalWellBeingToast.initialize(mTask);
+ // TODO(b/335606129) Investigate the usage of [TaskOverlay] in the new TaskThumbnailView.
+ // and if it's still necessary we should support that in the new TTV class.
+ if (!enableRefactorTaskThumbnail()) {
+ mTaskThumbnailViewDeprecated.getTaskOverlay().updateOrientationState(orientationState);
+ }
+ mDigitalWellBeingToast.initialize(getFirstTask());
}
/**
@@ -1231,11 +1308,6 @@
return deviceProfile.isTablet && !isFocusedTask();
}
- /** Whether this task view represents the desktop */
- public boolean isDesktopTask() {
- return false;
- }
-
/**
* Called to animate a smooth transition when going directly from an app into Overview (and
* vice versa). Icons fade in, and DWB banners slide in with a "shift up" animation.
@@ -1308,7 +1380,10 @@
setAlpha(mStableAlpha);
setIconScaleAndDim(1);
setColorTint(0, 0);
- mSnapshotView.resetViewTransforms();
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/335399428) add split select functionality to new TTV
+ mTaskThumbnailViewDeprecated.resetViewTransforms();
+ }
}
public void setStableAlpha(float parentAlpha) {
@@ -1321,7 +1396,12 @@
resetPersistentViewTransforms();
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
- mSnapshotView.setThumbnail(mTask, null);
+ // TODO(b/334825222): Implement thumbnail/snapshot for the new [TaskThumbnailView].
+ if (enableRefactorTaskThumbnail()) {
+ notifyIsRunningTaskUpdated();
+ } else {
+ mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(), null);
+ }
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
mBorderEnabled = false;
@@ -1334,12 +1414,14 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (mContainer.getDeviceProfile().isTablet) {
+ DeviceProfile deviceProfile = mContainer.getDeviceProfile();
+ int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+ if (deviceProfile.isTablet) {
setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
- setPivotY(mSnapshotView.getTop());
+ setPivotY(thumbnailTopMargin);
} else {
setPivotX((right - left) * 0.5f);
- setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
+ setPivotY(thumbnailTopMargin + (getHeight() - thumbnailTopMargin) * 0.5f);
}
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
@@ -1385,6 +1467,9 @@
scale *= mDismissScale;
setScaleX(scale);
setScaleY(scale);
+ if (enableRefactorTaskThumbnail()) {
+ mTaskViewData.getScale().setValue(scale);
+ }
updateSnapshotRadius();
}
@@ -1407,11 +1492,17 @@
}
protected void applyThumbnailSplashAlpha() {
- mSnapshotView.setSplashAlpha(mTaskThumbnailSplashAlpha);
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334826842) add splash functionality to new TTV
+ mTaskThumbnailViewDeprecated.setSplashAlpha(mTaskThumbnailSplashAlpha);
+ }
}
protected void refreshTaskThumbnailSplash() {
- mSnapshotView.refreshSplashView();
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334826842) add splash functionality to new TTV
+ mTaskThumbnailViewDeprecated.refreshSplashView();
+ }
}
private void setSplitSelectTranslationX(float x) {
@@ -1609,10 +1700,7 @@
getContext().getText(R.string.accessibility_close)));
final Context context = getContext();
- for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
- if (taskContainer == null) {
- continue;
- }
+ for (TaskContainer taskContainer : mTaskContainers) {
for (SystemShortcut s : TraceHelper.allowIpcs(
"TV.a11yInfo", () -> getEnabledShortcuts(this, taskContainer))) {
info.addAction(s.createAccessibilityAction(context));
@@ -1647,10 +1735,7 @@
return true;
}
- for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
- if (taskContainer == null) {
- continue;
- }
+ for (TaskContainer taskContainer : mTaskContainers) {
for (SystemShortcut s : getEnabledShortcuts(this,
taskContainer)) {
if (s.hasHandlerForAction(action)) {
@@ -1664,8 +1749,8 @@
}
@Nullable
- public RecentsView getRecentsView() {
- return (RecentsView) getParent();
+ public RecentsView<?, ?> getRecentsView() {
+ return (RecentsView<?, ?>) getParent();
}
RecentsPagedOrientationHandler getPagedOrientationHandler() {
@@ -1674,8 +1759,9 @@
private void notifyTaskLaunchFailed(String tag) {
String msg = "Failed to launch task";
- if (mTask != null) {
- msg += " (task=" + mTask.key.baseIntent + " userId=" + mTask.key.userId + ")";
+ if (getFirstTask() != null) {
+ msg += " (task=" + getFirstTask().key.baseIntent + " userId="
+ + getFirstTask().key.userId + ")";
}
Log.w(tag, msg);
Toast.makeText(getContext(), R.string.activity_not_available, LENGTH_SHORT).show();
@@ -1690,7 +1776,8 @@
progress = Utilities.boundToRange(progress, 0, 1);
mFullscreenProgress = progress;
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
- mSnapshotView.getTaskOverlay().setFullscreenProgress(progress);
+ mTaskThumbnailViewDeprecated.getTaskOverlay().setFullscreenProgress(progress);
+
RecentsView recentsView = mContainer.getOverviewPanel();
// Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
// oversized and banner would look disproportionately large.
@@ -1703,7 +1790,7 @@
protected void updateSnapshotRadius() {
updateCurrentFullscreenParams();
- mSnapshotView.setFullscreenParams(mCurrentFullscreenParams);
+ mTaskThumbnailViewDeprecated.setFullscreenParams(mCurrentFullscreenParams);
}
void updateCurrentFullscreenParams() {
@@ -1714,8 +1801,8 @@
if (getRecentsView() == null) {
return;
}
- fullscreenParams.setProgress(mFullscreenProgress, getRecentsView().getScaleX(),
- getScaleX());
+ fullscreenParams.setProgress(
+ mFullscreenProgress, getRecentsView().getScaleX(), getScaleX());
}
/**
@@ -1816,7 +1903,11 @@
}
public void setOverlayEnabled(boolean overlayEnabled) {
- mSnapshotView.setOverlayEnabled(overlayEnabled);
+ // TODO(b/335606129) Investigate the usage of [TaskOverlay] in the new TaskThumbnailView.
+ // and if it's still necessary we should support that in the new TTV class.
+ if (!enableRefactorTaskThumbnail()) {
+ mTaskThumbnailViewDeprecated.setOverlayEnabled(overlayEnabled);
+ }
}
public void initiateSplitSelect(SplitPositionOption splitPositionOption) {
@@ -1828,20 +1919,23 @@
* Set a color tint on the snapshot and supporting views.
*/
public void setColorTint(float amount, int tintColor) {
- mSnapshotView.setDimAlpha(amount);
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334832108) Add scrim to new TTV
+ mTaskThumbnailViewDeprecated.setDimAlpha(amount);
+ }
mIconView.setIconColorTint(tintColor, amount);
mDigitalWellBeingToast.setBannerColorTint(tintColor, amount);
}
private int getRootViewDisplayId() {
- Display display = getRootView().getDisplay();
+ Display display = getRootView().getDisplay();
return display != null ? display.getDisplayId() : DEFAULT_DISPLAY;
}
/**
- * Sets visibility for the thumbnail and associated elements (DWB banners and action chips).
- * IconView is unaffected.
+ * Sets visibility for the thumbnail and associated elements (DWB banners and action chips).
+ * IconView is unaffected.
*
* @param taskId is only used when setting visibility to a non-{@link View#VISIBLE} value
*/
@@ -1854,10 +1948,14 @@
}
}
+ private View getSnapshotView() {
+ return enableRefactorTaskThumbnail() ? mTaskThumbnailView : mTaskThumbnailViewDeprecated;
+ }
+
/**
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
*/
- public static class FullscreenDrawParams {
+ public static class FullscreenDrawParams implements SafeCloseable {
private float mCornerRadius;
private float mWindowCornerRadius;
@@ -1892,28 +1990,38 @@
Utilities.mapRange(fullscreenProgress, mCornerRadius, mWindowCornerRadius)
/ parentScale / taskViewScale;
}
+
+ @Override
+ public void close() {
+ }
}
- public class TaskIdAttributeContainer {
- private final TaskThumbnailView mThumbnailView;
+ /**
+ * Holder for all Task dependent information.
+ */
+ public class TaskContainer {
+ private final TaskThumbnailViewDeprecated mThumbnailView;
private final Task mTask;
private final TaskViewIcon mIconView;
/** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
private @SplitConfigurationOptions.StagePosition int mStagePosition;
@IdRes
private final int mA11yNodeId;
+ private final DigitalWellBeingToast mDigitalWellBeingToast;
- public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
- TaskViewIcon iconView, int stagePosition) {
+ public TaskContainer(Task task, TaskThumbnailViewDeprecated thumbnailView,
+ TaskViewIcon iconView, int stagePosition,
+ DigitalWellBeingToast digitalWellBeingToast) {
this.mTask = task;
this.mThumbnailView = thumbnailView;
this.mIconView = iconView;
this.mStagePosition = stagePosition;
this.mA11yNodeId = (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) ?
R.id.split_bottomRight_appInfo : R.id.split_topLeft_appInfo;
+ this.mDigitalWellBeingToast = digitalWellBeingToast;
}
- public TaskThumbnailView getThumbnailView() {
+ public TaskThumbnailViewDeprecated getThumbnailView() {
return mThumbnailView;
}
@@ -1944,5 +2052,9 @@
public int getA11yNodeId() {
return mA11yNodeId;
}
+
+ public DigitalWellBeingToast getDigitalWellBeingToast() {
+ return mDigitalWellBeingToast;
+ }
}
}
diff --git a/quickstep/tests/OWNERS b/quickstep/tests/OWNERS
index c271803..02e8ebc 100644
--- a/quickstep/tests/OWNERS
+++ b/quickstep/tests/OWNERS
@@ -2,4 +2,3 @@
sunnygoyal@google.com
winsonc@google.com
hyunyoungs@google.com
-mateuszc@google.com
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 58be345..0f06d98 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -12,10 +12,10 @@
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
-import static com.android.quickstep.OverviewCommandHelper.TYPE_HOME;
-import static com.android.quickstep.OverviewCommandHelper.TYPE_TOGGLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
@@ -31,7 +31,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.logging.StatsLogManager;
-import com.android.quickstep.OverviewCommandHelper;
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.AssistUtils;
@@ -52,8 +52,6 @@
@Mock
TouchInteractionService mockService;
@Mock
- OverviewCommandHelper mockCommandHelper;
- @Mock
Handler mockHandler;
@Mock
AssistUtils mockAssistUtils;
@@ -68,13 +66,26 @@
@Mock
View mockView;
+ private int mHomePressCount;
+ private int mOverviewToggleCount;
+ private final TaskbarNavButtonCallbacks mCallbacks = new TaskbarNavButtonCallbacks() {
+ @Override
+ public void onNavigateHome() {
+ mHomePressCount++;
+ }
+
+ @Override
+ public void onToggleOverview() {
+ mOverviewToggleCount++;
+ }
+ };
+
private TaskbarNavButtonController mNavButtonController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
- when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
when(mockService.getApplicationContext())
.thenReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
.getApplicationContext());
@@ -82,8 +93,12 @@
when(mockTaskbarControllers.getTaskbarActivityContext())
.thenReturn(mockTaskbarActivityContext);
doReturn(mockStatsLogManager).when(mockTaskbarActivityContext).getStatsLogManager();
- mNavButtonController = new TaskbarNavButtonController(mockService,
- mockSystemUiProxy, mockHandler, mockAssistUtils);
+ mNavButtonController = new TaskbarNavButtonController(
+ mockService,
+ mCallbacks,
+ mockSystemUiProxy,
+ mockHandler,
+ mockAssistUtils);
}
@Test
@@ -154,20 +169,20 @@
@Test
public void testPressHome() {
mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
- verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
+ assertThat(mHomePressCount).isEqualTo(1);
}
@Test
public void testPressRecents() {
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
- verify(mockCommandHelper, times(1)).addCommand(TYPE_TOGGLE);
+ assertThat(mOverviewToggleCount).isEqualTo(1);
}
@Test
- public void testPressRecentsWithScreenPinned() {
+ public void testPressRecentsWithScreenPinned_noNavigationToOverview() {
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
- verify(mockCommandHelper, times(0)).addCommand(TYPE_TOGGLE);
+ assertThat(mOverviewToggleCount).isEqualTo(0);
}
@Test
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/OWNERS
similarity index 100%
rename from quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/OWNERS
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 d90e048..7ad432b 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
@@ -22,7 +22,6 @@
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
-import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.widget.FrameLayout
import androidx.core.graphics.drawable.toBitmap
@@ -44,7 +43,10 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@SmallTest
@@ -52,19 +54,333 @@
class BubbleBarViewAnimatorTest {
private val context = ApplicationProvider.getApplicationContext<Context>()
- private val animatorScheduler = TestBubbleBarViewAnimatorScheduler()
+ private lateinit var animatorScheduler: TestBubbleBarViewAnimatorScheduler
+ private lateinit var overflowView: BubbleView
+ private lateinit var bubbleView: BubbleView
+ private lateinit var bubble: BubbleBarBubble
+ private lateinit var bubbleBarView: BubbleBarView
+ private lateinit var bubbleStashController: BubbleStashController
@Before
fun setUp() {
+ animatorScheduler = TestBubbleBarViewAnimatorScheduler()
PhysicsAnimatorTestUtils.prepareForTest()
}
@Test
fun animateBubbleInForStashed() {
- lateinit var overflowView: BubbleView
- lateinit var bubbleView: BubbleView
- lateinit var bubble: BubbleBarBubble
- val bubbleBarView = BubbleBarView(context)
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble)
+ }
+
+ // let the animation start and wait for it to complete
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(handle.alpha).isEqualTo(0)
+ assertThat(handle.translationY)
+ .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(1)
+ assertThat(bubbleBarView.scaleY).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+
+ // execute the hide bubble animation
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+ // let the animation start and wait for it to complete
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(handle.alpha).isEqualTo(1)
+ assertThat(handle.translationY).isEqualTo(0)
+ assertThat(bubbleBarView.alpha).isEqualTo(0)
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ verify(bubbleStashController).stashBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateBubbleInForStashed_tapAnimatingBubble() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble)
+ }
+
+ // let the animation start and wait for it to complete
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(handle.alpha).isEqualTo(0)
+ assertThat(handle.translationY)
+ .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+ assertThat(bubbleBarView.scaleX).isEqualTo(1)
+ assertThat(bubbleBarView.scaleY).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+
+ verify(bubbleStashController, atLeastOnce()).updateTaskbarTouchRegion()
+
+ // verify the hide bubble animation is pending
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ animator.onBubbleBarTouchedWhileAnimating()
+
+ assertThat(animatorScheduler.delayedBlock).isNull()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ }
+
+ @Test
+ fun animateBubbleInForStashed_touchTaskbarArea_whileShowing() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble)
+ }
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
+
+ assertThat(handleAnimator.isRunning()).isTrue()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ // verify the hide bubble animation is pending
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.onStashStateChangingWhileAnimating()
+ }
+
+ // verify that the hide animation was canceled
+ assertThat(animatorScheduler.delayedBlock).isNull()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
+
+ // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
+ // again
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ assertThat(handleAnimator.isRunning()).isFalse()
+ }
+
+ @Test
+ fun animateBubbleInForStashed_touchTaskbarArea_whileHiding() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble)
+ }
+
+ // let the animation start and wait for it to complete
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ // execute the hide bubble animation
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+ // wait for the hide animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ assertThat(handleAnimator.isRunning()).isTrue()
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.onStashStateChangingWhileAnimating()
+ }
+
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
+
+ // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
+ // again
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ assertThat(handleAnimator.isRunning()).isFalse()
+ }
+
+ @Test
+ fun animateBubbleInForStashed_showAnimationCanceled() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateBubbleInForStashed(bubble)
+ }
+
+ // wait for the animation to start
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true }
+
+ assertThat(handleAnimator.isRunning()).isTrue()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+
+ handleAnimator.cancel()
+ assertThat(handleAnimator.isRunning()).isFalse()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(animatorScheduler.delayedBlock).isNull()
+ }
+
+ @Test
+ fun animateToInitialState_inApp() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = true, isExpanding = false)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(barAnimator.isRunning()).isFalse()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(bubbleBarView.alpha).isEqualTo(0)
+ assertThat(handle.translationY).isEqualTo(0)
+ assertThat(handle.alpha).isEqualTo(1)
+
+ verify(bubbleStashController).stashBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateToInitialState_inApp_autoExpanding() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = true, isExpanding = true)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(barAnimator.isRunning()).isFalse()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateToInitialState_inHome() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(barAnimator.isRunning()).isFalse()
+ assertThat(bubbleBarView.isAnimatingNewBubble).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(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
+ private fun setUpBubbleBar() {
+ bubbleBarView = BubbleBarView(context)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0)
val inflater = LayoutInflater.from(context)
@@ -84,64 +400,41 @@
bubbleBarView.addView(bubbleView)
}
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ }
- val bubbleStashController = mock<BubbleStashController>()
+ private fun setUpBubbleStashController() {
+ bubbleStashController = mock<BubbleStashController>()
whenever(bubbleStashController.isStashed).thenReturn(true)
-
- val handle = View(context)
- val handleAnimator = PhysicsAnimator.getInstance(handle)
- whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
-
- val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
-
- InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.animateBubbleInForStashed(bubble)
- }
-
- // let the animation start and wait for it to complete
- InstrumentationRegistry.getInstrumentation().waitForIdleSync()
- PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
- assertThat(handle.alpha).isEqualTo(0)
- assertThat(handle.translationY).isEqualTo(-70)
- assertThat(overflowView.visibility).isEqualTo(INVISIBLE)
- assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
- assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
- assertThat(bubbleView.alpha).isEqualTo(1)
- assertThat(bubbleView.translationY).isEqualTo(-20)
- assertThat(bubbleView.scaleY).isEqualTo(1)
-
- // execute the hide bubble animation
- assertThat(animatorScheduler.delayedBlock).isNotNull()
- InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
-
- // let the animation start and wait for it to complete
- InstrumentationRegistry.getInstrumentation().waitForIdleSync()
- PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
- assertThat(bubbleView.alpha).isEqualTo(1)
- assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
- assertThat(bubbleView.translationY).isEqualTo(0)
- assertThat(bubbleBarView.alpha).isEqualTo(0)
- assertThat(overflowView.alpha).isEqualTo(1)
- assertThat(overflowView.visibility).isEqualTo(VISIBLE)
- assertThat(handle.alpha).isEqualTo(1)
- assertThat(handle.translationY).isEqualTo(0)
+ whenever(bubbleStashController.diffBetweenHandleAndBarCenters)
+ .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS)
+ whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation)
+ .thenReturn(HANDLE_TRANSLATION)
+ whenever(bubbleStashController.bubbleBarTranslationYForTaskbar)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
}
private class TestBubbleBarViewAnimatorScheduler : BubbleBarViewAnimator.Scheduler {
- var delayedBlock: (() -> Unit)? = null
+ var delayedBlock: Runnable? = null
private set
- override fun post(block: () -> Unit) {
- block.invoke()
+ override fun post(block: Runnable) {
+ block.run()
}
- override fun postDelayed(delayMillis: Long, block: () -> Unit) {
+ override fun postDelayed(delayMillis: Long, block: Runnable) {
check(delayedBlock == null) { "there is already a pending block waiting to run" }
delayedBlock = block
}
+
+ override fun cancel(block: Runnable) {
+ check(delayedBlock == block) { "the pending block does not match the canceled block" }
+ delayedBlock = null
+ }
}
}
+
+private const val DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS = -20f
+private const val HANDLE_TRANSLATION = -30f
+private const val BAR_TRANSLATION_Y_FOR_TASKBAR = -50f
+private const val BAR_TRANSLATION_Y_FOR_HOTSEAT = -40f
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index c327166..c8f7946 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -17,8 +17,6 @@
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
-import com.android.systemui.shared.rotation.RotationButton
-import java.lang.IllegalStateException
import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
@@ -39,10 +37,9 @@
private val mockRecentsButton: ImageView = mock()
private val mockHomeButton: ImageView = mock()
private val mockImeSwitcher: ImageView = mock()
- private val mockRotationButton: RotationButton = mock()
private val mockA11yButton: ImageView = mock()
private val mockSpace: Space = mock()
- private val mockConfiguration: Configuration = mock();
+ private val mockConfiguration: Configuration = mock()
private var surfaceRotation = Surface.ROTATION_0
@@ -210,7 +207,6 @@
phoneMode = phoneMode,
surfaceRotation = surfaceRotation,
imeSwitcher = mockImeSwitcher,
- rotationButton = mockRotationButton,
a11yButton = mockA11yButton,
space = mockSpace,
)
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
new file mode 100644
index 0000000..efd7bec
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -0,0 +1,79 @@
+/*
+ * 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 androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.viewmodel.TaskViewData
+import com.android.systemui.shared.recents.model.Task
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TaskThumbnailViewModelTest {
+ private val recentsViewData = RecentsViewData()
+ private val taskViewData = TaskViewData()
+ private val systemUnderTest = TaskThumbnailViewModel(recentsViewData, taskViewData)
+
+ @Test
+ fun initialStateIsUninitialized() = runTest {
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+ }
+
+ @Test
+ fun bindRunningTask_thenStateIs_LiveTile() = runTest {
+ val taskThumbnail = TaskThumbnail(Task(), isRunning = true)
+ systemUnderTest.bind(taskThumbnail)
+
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+ }
+
+ @Test
+ fun setRecentsFullscreenProgress_thenProgressIsPassedThrough() = runTest {
+ recentsViewData.fullscreenProgress.value = 0.5f
+
+ assertThat(systemUnderTest.recentsFullscreenProgress.first()).isEqualTo(0.5f)
+
+ recentsViewData.fullscreenProgress.value = 0.6f
+
+ assertThat(systemUnderTest.recentsFullscreenProgress.first()).isEqualTo(0.6f)
+ }
+
+ @Test
+ fun setAncestorScales_thenScaleIsCalculated() = runTest {
+ recentsViewData.scale.value = 0.5f
+ taskViewData.scale.value = 0.6f
+
+ assertThat(systemUnderTest.inheritedScale.first()).isEqualTo(0.3f)
+ }
+
+ @Test
+ fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() = runTest {
+ // TODO(b/334825222): Change the expectation here when snapshot state is implemented
+ val task = Task()
+ val runningTask = TaskThumbnail(task, isRunning = true)
+ val stoppedTask = TaskThumbnail(task, isRunning = false)
+ systemUnderTest.bind(runningTask)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+
+ systemUnderTest.bind(stoppedTask)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 9fa4b79..72cfd92 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -44,7 +44,6 @@
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.quickstep.FallbackActivityInterface;
-import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.SurfaceTransaction.MockProperties;
import org.hamcrest.Description;
@@ -160,7 +159,6 @@
void verifyNoTransforms() {
LauncherModelHelper helper = new LauncherModelHelper();
try {
- helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
int rotation = mDisplaySize.x > mDisplaySize.y
? Surface.ROTATION_90 : Surface.ROTATION_0;
CachedDisplayInfo cdi = new CachedDisplayInfo(mDisplaySize, rotation);
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
new file mode 100644
index 0000000..4fafde8
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Process
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidTestingRunner::class)
+class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
+
+ @get:Rule val mockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var mockRecentsModel: RecentsModel
+ @Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
+
+ private var nextTaskId: Int = 500
+
+ private lateinit var taskbarRunningAppsController: DesktopTaskbarRunningAppsController
+ private lateinit var userHandle: UserHandle
+
+ @Before
+ fun setUp() {
+ super.setup()
+ userHandle = Process.myUserHandle()
+ taskbarRunningAppsController =
+ DesktopTaskbarRunningAppsController(mockRecentsModel) {
+ mockDesktopVisibilityController
+ }
+ taskbarRunningAppsController.init(taskbarControllers)
+ taskbarRunningAppsController.setApps(
+ ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray()
+ )
+ }
+
+ @Test
+ fun updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItems() {
+ setInDesktopMode(false)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
+ .isEqualTo(hotseatItems.toTypedArray())
+ }
+
+ @Test
+ fun updateHotseatItemInfos_notInDesktopMode_runningApps_returnsExistingHotseatItems() {
+ setInDesktopMode(false)
+ val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
+ val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages)
+ val runningTasks =
+ createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps()
+
+ val newHotseatItems =
+ taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+ assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(hotseatPackages)
+ }
+
+ @Test
+ fun updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItems() {
+ setInDesktopMode(true)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
+ .isEqualTo(hotseatItems.toTypedArray())
+ }
+
+ @Test
+ fun updateHotseatItemInfos_returnsExistingHotseatItemsAndRunningApps() {
+ setInDesktopMode(true)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ val runningTasks =
+ createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps()
+
+ val newHotseatItems =
+ taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+ val expectedPackages =
+ listOf(
+ HOTSEAT_PACKAGE_1,
+ HOTSEAT_PACKAGE_2,
+ RUNNING_APP_PACKAGE_1,
+ RUNNING_APP_PACKAGE_2,
+ )
+ assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+ }
+
+ @Test
+ fun updateHotseatItemInfos_runningAppIsHotseatItem_returnsDistinctItems() {
+ setInDesktopMode(true)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ val runningTasks =
+ createDesktopTasksFromPackageNames(
+ listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
+ )
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps()
+
+ val newHotseatItems =
+ taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+ val expectedPackages =
+ listOf(
+ HOTSEAT_PACKAGE_1,
+ HOTSEAT_PACKAGE_2,
+ RUNNING_APP_PACKAGE_1,
+ RUNNING_APP_PACKAGE_2,
+ )
+ assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+ }
+
+ @Test
+ fun getRunningApps_notInDesktopMode_returnsEmptySet() {
+ setInDesktopMode(false)
+ val runningTasks =
+ createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps()
+
+ assertThat(taskbarRunningAppsController.runningApps).isEqualTo(emptySet<String>())
+ }
+
+ @Test
+ fun getRunningApps_inDesktopMode_returnsRunningApps() {
+ setInDesktopMode(true)
+ val runningTasks =
+ createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps()
+
+ assertThat(taskbarRunningAppsController.runningApps)
+ .isEqualTo(setOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ }
+
+ private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
+ return packageNames.map { createTestAppInfo(packageName = it) }
+ }
+
+ private fun createDesktopTasksFromPackageNames(
+ packageNames: List<String>
+ ): ArrayList<RunningTaskInfo> {
+ return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
+ }
+
+ private fun createDesktopTaskInfo(packageName: String): RunningTaskInfo {
+ return RunningTaskInfo().apply {
+ taskId = nextTaskId++
+ configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
+ realActivity = ComponentName(packageName, "TestActivity")
+ }
+ }
+
+ private fun createTestAppInfo(
+ packageName: String = "testPackageName",
+ className: String = "testClassName"
+ ) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent())
+
+ private fun setInDesktopMode(inDesktopMode: Boolean) {
+ whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode)
+ }
+
+ private companion object {
+ const val HOTSEAT_PACKAGE_1 = "hotseat1"
+ const val HOTSEAT_PACKAGE_2 = "hotseat2"
+ const val RUNNING_APP_PACKAGE_1 = "running1"
+ const val RUNNING_APP_PACKAGE_2 = "running2"
+ const val RUNNING_APP_PACKAGE_3 = "running3"
+ val ALL_APP_PACKAGES =
+ listOf(
+ HOTSEAT_PACKAGE_1,
+ HOTSEAT_PACKAGE_2,
+ RUNNING_APP_PACKAGE_1,
+ RUNNING_APP_PACKAGE_2,
+ RUNNING_APP_PACKAGE_3,
+ )
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 0f9d96c..d59aafb 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -16,12 +16,12 @@
package com.android.quickstep
-import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.android.dx.mockito.inline.extended.StaticMockitoSession
import android.content.ComponentName
import android.content.Intent
import android.platform.test.flag.junit.SetFlagsRule
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.AbstractFloatingViewHelper
import com.android.launcher3.logging.StatsLogManager
@@ -39,12 +39,12 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.mockito.quality.Strictness
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
/** Test for DesktopSystemShortcut */
class DesktopSystemShortcutTest {
@@ -64,15 +64,18 @@
private lateinit var mockitoSession: StaticMockitoSession
@Before
- fun setUp(){
- mockitoSession = mockitoSession().strictness(Strictness.LENIENT)
- .spyStatic(DesktopModeStatus::class.java).startMocking()
+ fun setUp() {
+ mockitoSession =
+ mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java)
+ .startMocking()
doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
}
@After
- fun tearDown(){
+ fun tearDown() {
mockitoSession.finishMocking()
}
@@ -85,11 +88,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -106,11 +110,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -128,11 +133,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -148,11 +154,12 @@
isDockable = false
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -168,11 +175,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
whenever(launcher.getOverviewPanel<LauncherRecentsView>()).thenReturn(recentsView)
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 5b16c0f..2858929 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
-import static com.android.launcher3.testing.shared.TestProtocol.UPDATE_OVERVIEW_TARGETS_RUNNING_LATE;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_ACTIVITY_TIMEOUT;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_BROADCAST_TIMEOUT_SECS;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT;
@@ -43,7 +42,6 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.RemoteException;
-import android.util.Log;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -116,8 +114,6 @@
mDevice.setOrientationNatural();
mLauncher = AbstractLauncherUiTest.createLauncherInstrumentation();
mLauncher.enableDebugTracing();
- // b/143488140
- //mLauncher.enableCheckEventsForSuccessfulGestures();
if (TestHelpers.isInLauncherProcess()) {
Utilities.enableRunningInTestHarnessForTests();
@@ -133,13 +129,6 @@
getLauncherCommand(mOtherLauncherActivity));
updateHandler.mChangeCounter
.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "AFTER AWAIT: mObserver home intent package name="
- + updateHandler.mObserver.getHomeIntent()
- .getComponent().getPackageName());
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "AFTER AWAIT: mOtherLauncherActivity package name="
- + mOtherLauncherActivity.packageName);
try {
base.evaluate();
} finally {
@@ -147,7 +136,6 @@
TestCommandReceiver.callCommand(TestCommandReceiver.DISABLE_TEST_LAUNCHER);
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
getLauncherCommand(getLauncherInMyProcess()));
- // b/143488140
pressHomeAndWaitForOverviewClose();
}
}
@@ -191,8 +179,6 @@
}
}
- // b/143488140
- //@NavigationModeSwitch
@Test
public void goToOverviewFromHome() {
mDevice.pressHome();
@@ -261,10 +247,7 @@
DEFAULT_UI_TIMEOUT, mLauncher);
}
- // b/143488140
- //@NavigationModeSwitch
@Test
- @ScreenRecordRule.ScreenRecord // b/321775748
public void testOverview() throws IOException {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
@@ -348,25 +331,12 @@
mRads = new RecentsAnimationDeviceState(ctx);
mObserver = new OverviewComponentObserver(ctx, mRads);
mChangeCounter = new CountDownLatch(1);
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewUpdateHandler(Constructor): mObserver home intent package name="
- + mObserver.getHomeIntent().getComponent().getPackageName());
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewUpdateHandler(Constructor): mOtherLauncherActivity package name="
- + mOtherLauncherActivity.packageName);
if (mObserver.getHomeIntent().getComponent()
.getPackageName().equals(mOtherLauncherActivity.packageName)) {
// Home already same
mChangeCounter.countDown();
} else {
- mObserver.setOverviewChangeListener(b -> {
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewChangeListener(Callback): isHomeAndOverviewSame=" + b);
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewChangeListener(Callback): mObserver home intent package name="
- + mObserver.getHomeIntent().getComponent().getPackageName());
- mChangeCounter.countDown();
- });
+ mObserver.setOverviewChangeListener(b -> mChangeCounter.countDown());
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index df88726..094fd4c 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -205,11 +205,10 @@
boolean condition, Description description) {
launcher.checkForAnomaly(true, true);
if (!condition) {
- final AssertionError assertionError = new AssertionError(message);
if (description != null) {
- FailureWatcher.onError(launcher, description, assertionError);
+ FailureWatcher.onError(launcher, description);
}
- throw assertionError;
+ throw new AssertionError(message);
}
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 4aa7cb0..37ab131 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -86,8 +86,8 @@
final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
return getFromLauncher(launcher -> {
- assertTrue("Latest task is not Calculator",
- CALCULATOR_PACKAGE.equals(task.getTask().getTopComponent().getPackageName()));
+ assertTrue("Latest task is not Calculator", CALCULATOR_PACKAGE.equals(
+ task.getFirstTask().getTopComponent().getPackageName()));
return task.getDigitalWellBeingToast();
});
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 0c143b4..69a7664 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -21,16 +21,21 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
+import com.android.launcher3.allapps.PrivateProfileManager;
+import com.android.launcher3.tapl.HomeAllApps;
import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.PrivateSpaceContainer;
+import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.After;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,7 +47,9 @@
public class TaplPrivateSpaceTest extends AbstractQuickStepTest {
private int mProfileUserId;
- private boolean mPrivateProfileSetupSuccessful;
+
+ private static final String PRIVATE_PROFILE_NAME = "LauncherPrivateProfile";
+ private static final String INSTALLED_APP_NAME = "Aardwolf";
private static final String TAG = "TaplPrivateSpaceTest";
@Override
@@ -51,8 +58,6 @@
initialize(this);
createAndStartPrivateProfileUser();
- assumeTrue("Private Profile Setup not successful, aborting",
- mPrivateProfileSetupSuccessful);
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -71,7 +76,7 @@
private void createAndStartPrivateProfileUser() {
String createUserOutput = executeShellCommand("pm create-user --profileOf 0 --user-type "
- + "android.os.usertype.profile.PRIVATE LauncherPrivateProfile");
+ + "android.os.usertype.profile.PRIVATE " + PRIVATE_PROFILE_NAME);
updatePrivateProfileSetupSuccessful("pm create-user", createUserOutput);
String[] tokens = createUserOutput.split("\\s+");
mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
@@ -85,21 +90,133 @@
@After
public void removePrivateProfile() {
- String output = executeShellCommand("pm remove-user " + mProfileUserId);
- updateProfileRemovalSuccessful("pm remove-user", output);
- waitForPrivateSpaceRemoval();
+ String userListOutput = executeShellCommand("pm list users");
+ if (isPrivateProfilePresent("pm list users", userListOutput)) {
+ String output = executeShellCommand("pm remove-user " + mProfileUserId);
+ updateProfileRemovalSuccessful("pm remove-user", output);
+ waitForPrivateSpaceRemoval();
+ }
}
@Test
public void testPrivateSpaceContainerIsPresent() {
- assumeTrue(mPrivateProfileSetupSuccessful);
// Scroll to the bottom of All Apps
executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
- waitForResumed("Launcher internal state is still Background");
+ // Freeze All Apps
+ HomeAllApps homeAllApps = mLauncher.getAllApps();
+ homeAllApps.freeze();
- // Verify Unlocked View elements are present.
- assertNotNull("Private Space Unlocked View not found, or is not correct",
- mLauncher.getAllApps().getPrivateSpaceUnlockedView());
+ try {
+ // Verify Unlocked View elements are present.
+ assertNotNull("Private Space Unlocked View not found, or is not correct",
+ homeAllApps.getPrivateSpaceUnlockedView());
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord // b/334946529
+ public void testUserInstalledAppIsShownAboveDivider() throws IOException {
+ // Ensure that the App is not installed in main user otherwise, it may not be found in
+ // PS container.
+ TestUtil.uninstallDummyApp();
+ // Install the app in Private Profile
+ TestUtil.installDummyAppForUser(mProfileUserId);
+ waitForLauncherUIUpdate();
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+ // Freeze All Apps
+ HomeAllApps homeAllApps = mLauncher.getAllApps();
+ homeAllApps.freeze();
+
+ try {
+ // Verify the Installed App is displayed in correct position.
+ PrivateSpaceContainer psContainer = homeAllApps.getPrivateSpaceUnlockedView();
+ psContainer.verifyInstalledAppIsPresent(INSTALLED_APP_NAME);
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord // b/334946529
+ public void testPrivateSpaceAppLongPressUninstallMenu() throws IOException {
+ // Ensure that the App is not installed in main user otherwise, it may not be found in
+ // PS container.
+ TestUtil.uninstallDummyApp();
+ // Install the app in Private Profile
+ TestUtil.installDummyAppForUser(mProfileUserId);
+ waitForLauncherUIUpdate();
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+ // Freeze All Apps
+ HomeAllApps homeAllApps = mLauncher.getAllApps();
+ homeAllApps.freeze();
+
+ try {
+ // Get the "uninstall" menu item.
+ homeAllApps.getAppIcon(INSTALLED_APP_NAME).openMenu().getMenuItem("Uninstall");
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord // b/334946529
+ @Ignore("b/339179262")
+ public void testPrivateSpaceLockingBehaviour() throws IOException {
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+ HomeAllApps homeAllApps = mLauncher.getAllApps();
+
+ // Disable Private Space
+ togglePrivateSpace(PrivateProfileManager.STATE_DISABLED, homeAllApps);
+
+ homeAllApps.freeze();
+ try {
+ // Verify Locked View elements are present.
+ homeAllApps.getPrivateSpaceLockedView();
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+
+ // Enable Private Space
+ togglePrivateSpace(PrivateProfileManager.STATE_ENABLED, homeAllApps);
+
+ homeAllApps.freeze();
+ try {
+ // Verify UnLocked View elements are present.
+ homeAllApps.getPrivateSpaceUnlockedView();
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+ }
+
+ private void togglePrivateSpace(int state, HomeAllApps homeAllApps) {
+ homeAllApps.freeze();
+ try {
+ // Try Toggling Private Space
+ homeAllApps.togglePrivateSpace();
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+ PrivateProfileManager manager = getFromLauncher(l -> l.getAppsView()
+ .getPrivateProfileManager());
+ waitForLauncherCondition("Private profile toggle to state: " + state + " failed",
+ launcher -> {
+ manager.reset();
+ return manager.getCurrentState() == state;
+ },
+ LauncherInstrumentation.WAIT_TIME_MS);
+ // Wait for Launcher UI to be updated with Private Space Items.
+ waitForLauncherUIUpdate();
}
private void waitForPrivateSpaceSetup() {
@@ -127,7 +244,7 @@
private void updatePrivateProfileSetupSuccessful(String cli, String output) {
Log.d(TAG, "updatePrivateProfileSetupSuccessful, cli=" + cli + " " + "output="
+ output);
- mPrivateProfileSetupSuccessful = output.startsWith("Success");
+ assertTrue(output, output.startsWith("Success"));
}
private void updateProfileRemovalSuccessful(String cli, String output) {
@@ -135,6 +252,11 @@
assertTrue(output, output.startsWith("Success"));
}
+ private boolean isPrivateProfilePresent(String cli, String output) {
+ Log.d(TAG, "updatePrivateProfilePresent, cli=" + cli + " " + "output=" + output);
+ return output.contains(PRIVATE_PROFILE_NAME);
+ }
+
private String executeShellCommand(String command) {
try {
return mDevice.executeShellCommand(command);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index e4caa26..1886ce6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -35,7 +35,6 @@
@Before
public void setUp() throws Exception {
super.setUp();
- // b/143488140
mLauncher.goHome();
// Start an activity where the gestures start.
startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index a9ff161..df73e09 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -15,8 +15,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.TaskbarModeSwitchRule.Mode.PERSISTENT;
import android.graphics.Rect;
@@ -25,7 +23,6 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
@@ -48,7 +45,6 @@
@Test
@NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
public void testThreeButtonsTaskbarBoundsAfterConfigChangeDuringIme() {
Rect taskbarBoundsBefore = getTaskbar().getVisibleBounds();
// Go home and to an IME activity (any configuration change would do, as long as it
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 81a2d54..7877e8a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -181,12 +181,6 @@
public void testOverviewActions() throws Exception {
assumeFalse("Skipping Overview Actions tests for grid only overview",
mLauncher.isTablet() && mLauncher.isGridOnlyOverviewEnabled());
- // Experimenting for b/165029151:
- final Overview overview = mLauncher.goHome().switchToOverview();
- if (overview.hasTasks()) overview.dismissAllTasks();
- mLauncher.goHome();
- //
-
startTestAppsWithCheck();
OverviewActions actionsView =
mLauncher.goHome().switchToOverview().getOverviewActions();
@@ -434,9 +428,7 @@
@Test
@PortraitLandscape
@TaskbarModeSwitch()
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/309820115
@Ignore("b/315376057")
- @ScreenRecord // b/309820115
public void testOverviewForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 2a54057..bfd7bdb 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -130,7 +130,7 @@
.tapMenu()
.hasMenuItem("Save app pair"));
} else {
- overview.getOverviewActions().assertHasAction("Save app pair");
+ overview.getOverviewGroupActions().assertHasAction("Save app pair");
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index f0683f9..ec245ee 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.PERSISTENT;
import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.TRANSIENT;
@@ -53,7 +55,7 @@
@Override
public void setUp() throws Exception {
- mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext);
+ mTaskbarWasInTransientMode = isTaskbarInTransientMode(getTargetContext());
setTaskbarMode(mLauncher, isTaskbarTestModeTransient());
super.setUp();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 374722e..e4f8b6c 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -16,6 +16,8 @@
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;
@@ -30,6 +32,8 @@
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;
@@ -84,6 +88,8 @@
@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/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
index 8eec903..512557b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
@@ -17,9 +17,11 @@
package com.android.quickstep;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,7 +36,6 @@
import androidx.test.filters.SmallTest;
-import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.util.BorderAnimator;
import com.android.quickstep.views.TaskView;
@@ -74,6 +75,7 @@
@Test
public void notShowBorderOnBorderDisabled() {
+ presetBorderStatus(/* enabled= */ true);
mTaskView.setBorderEnabled(/* enabled= */ false);
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
mTaskView.onHoverEvent(MotionEvent.obtain(event));
@@ -86,7 +88,7 @@
}
@Test
- public void showBorderOnBorderEnabled() {
+ public void showBorderOnHoverEvent() {
mTaskView.setBorderEnabled(/* enabled= */ true);
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
mTaskView.onHoverEvent(MotionEvent.obtain(event));
@@ -98,7 +100,18 @@
}
@Test
+ public void showBorderOnBorderEnabled() {
+ presetBorderStatus(/* enabled= */ false);
+ mTaskView.setBorderEnabled(/* enabled= */ true);
+ verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+ true);
+ verify(mFocusAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+ true);
+ }
+
+ @Test
public void hideBorderOnBorderDisabled() {
+ presetBorderStatus(/* enabled= */ true);
mTaskView.setBorderEnabled(/* enabled= */ false);
verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ false, /* animated= */
true);
@@ -107,13 +120,35 @@
}
@Test
+ public void notTriggerAnimatorWhenEnableStatusUnchanged() {
+ presetBorderStatus(/* enabled= */ false);
+ // Border is disabled by default, no animator is triggered after it is disabled again
+ mTaskView.setBorderEnabled(/* enabled= */ false);
+ verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+ anyBoolean(), /* animated= */ anyBoolean());
+ verify(mFocusAnimator, never()).setBorderVisibility(/* visible= */
+ anyBoolean(), /* animated= */ anyBoolean());
+ }
+
+ private void presetBorderStatus(boolean enabled) {
+ // Make the task view focused and hovered
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
+ mTaskView.onHoverEvent(MotionEvent.obtain(event));
+ mTaskView.requestFocus();
+ mTaskView.setBorderEnabled(/* enabled= */ enabled);
+ // Reset invocation count after presetting status
+ reset(mHoverAnimator);
+ reset(mFocusAnimator);
+ }
+
+ @Test
public void notShowBorderByDefault() {
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
mTaskView.onHoverEvent(MotionEvent.obtain(event));
- verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
- true);
+ verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+ anyBoolean(), /* animated= */ anyBoolean());
mTaskView.onFocusChanged(true, 0, new Rect());
- verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
- true);
+ verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+ anyBoolean(), /* animated= */ anyBoolean());
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
index e5657fb..84ceb33 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
@@ -130,11 +130,10 @@
boolean condition, Description description) {
launcher.checkForAnomaly(true, true);
if (!condition) {
- final AssertionError assertionError = new AssertionError(message);
if (description != null) {
- FailureWatcher.onError(launcher, description, assertionError);
+ FailureWatcher.onError(launcher, description);
}
- throw assertionError;
+ throw new AssertionError(message);
}
}
}
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 dbe4624..4d10f0f 100644
--- a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
@@ -53,7 +54,13 @@
class TaskbarPinningControllerTest : TaskbarBaseTestCase() {
private val taskbarDragLayer = mock<TaskbarDragLayer>()
private val taskbarSharedState = mock<TaskbarSharedState>()
- private val launcherPrefs = mock<LauncherPrefs> { on { get(TASKBAR_PINNING) } doReturn false }
+ private var isInDesktopMode = false
+ private val isInDesktopModeProvider = { isInDesktopMode }
+ private val launcherPrefs =
+ mock<LauncherPrefs> {
+ on { get(TASKBAR_PINNING) } doReturn false
+ on { get(TASKBAR_PINNING_IN_DESKTOP_MODE) } doReturn false
+ }
private val statsLogger = mock<StatsLogManager.StatsLogger>()
private val statsLogManager = mock<StatsLogManager> { on { logger() } doReturn statsLogger }
private lateinit var pinningController: TaskbarPinningController
@@ -64,7 +71,8 @@
whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs)
whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer)
whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager)
- pinningController = spy(TaskbarPinningController(taskbarActivityContext))
+ pinningController =
+ spy(TaskbarPinningController(taskbarActivityContext, isInDesktopModeProvider))
pinningController.init(taskbarControllers, taskbarSharedState)
}
@@ -95,7 +103,7 @@
}
@Test
- fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToPinnedTaskbar() {
+ fun testOnCloseCallback_whenLauncherPreferenceChanged_shouldAnimateToPinnedTaskbar() {
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
doNothing().whenever(pinningController).animateTaskbarPinning(any())
@@ -106,7 +114,7 @@
}
@Test
- fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToTransientTaskbar() {
+ fun testOnCloseCallback_whenLauncherPreferenceChanged_shouldAnimateToTransientTaskbar() {
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true)
doNothing().whenever(pinningController).animateTaskbarPinning(any())
@@ -199,4 +207,13 @@
assertThat(pinningController.isAnimatingTaskbarPinning).isFalse()
verify(launcherPrefs, times(1)).put(TASKBAR_PINNING, true)
}
+
+ @Test
+ fun testRecreateTaskbarAndUpdatePinningValue_whenAnimationEnds_shouldUpdateTaskbarPinningDesktopModePref() {
+ isInDesktopMode = true
+ pinningController.recreateTaskbarAndUpdatePinningValue()
+ verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(false)
+ assertThat(pinningController.isAnimatingTaskbarPinning).isFalse()
+ verify(launcherPrefs, times(1)).put(TASKBAR_PINNING_IN_DESKTOP_MODE, true)
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
index adaf7ff..ece67af 100644
--- a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
@@ -43,6 +43,7 @@
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.never
import org.mockito.kotlin.spy
@@ -100,8 +101,7 @@
// Stub methods on appPairsController so that they return mocks
spyAppPairsController = spy(appPairsController)
whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
- whenever(spyAppPairsController.getTopTaskTracker(mockTaskbarActivityContext))
- .thenReturn(mockTopTaskTracker)
+ doReturn(mockTopTaskTracker).whenever(spyAppPairsController).topTaskTracker
whenever(mockTopTaskTracker.getCachedTopTask(any())).thenReturn(mockCachedTaskInfo)
whenever(mockTask1.getKey()).thenReturn(mockTaskKey1)
whenever(mockTask2.getKey()).thenReturn(mockTaskKey2)
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index 68c9bf9..f29df61 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -17,6 +17,8 @@
package com.android.quickstep.util
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.ContextThemeWrapper
@@ -31,16 +33,18 @@
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.views.GroupedTaskView
import com.android.quickstep.views.IconView
-import com.android.quickstep.views.TaskThumbnailView
+import com.android.quickstep.views.TaskThumbnailViewDeprecated
import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
import com.android.systemui.shared.recents.model.Task
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
import org.mockito.kotlin.any
import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
@@ -55,7 +59,7 @@
private val mockSplitSelectStateController: SplitSelectStateController = mock()
// TaskView
private val mockTaskView: TaskView = mock()
- private val mockThumbnailView: TaskThumbnailView = mock()
+ private val mockThumbnailView: TaskThumbnailViewDeprecated = mock()
private val mockBitmap: Bitmap = mock()
private val mockIconView: IconView = mock()
private val mockTaskViewDrawable: Drawable = mock()
@@ -63,7 +67,7 @@
private val mockGroupedTaskView: GroupedTaskView = mock()
private val mockTask: Task = mock()
private val mockTaskKey: Task.TaskKey = mock()
- private val mockTaskIdAttributeContainer: TaskIdAttributeContainer = mock()
+ private val mockTaskContainer: TaskContainer = mock()
// AppPairIcon
private val mockAppPairIcon: AppPairIcon = mock()
private val mockContextThemeWrapper: ContextThemeWrapper = mock()
@@ -79,14 +83,15 @@
private val transitionInfo: TransitionInfo = mock()
private val transaction: Transaction = mock()
- lateinit var splitAnimationController: SplitAnimationController
+ private lateinit var splitAnimationController: SplitAnimationController
@Before
fun setup() {
- whenever(mockTaskView.thumbnail).thenReturn(mockThumbnailView)
+ whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView)
whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap)
- whenever(mockTaskView.iconView).thenReturn(mockIconView)
+ whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
+ whenever(mockTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
whenever(splitSelectSource.drawable).thenReturn(mockSplitSourceDrawable)
whenever(splitSelectSource.view).thenReturn(mockSplitSourceView)
@@ -173,14 +178,13 @@
// Remove icon view from GroupedTaskView
whenever(mockIconView.drawable).thenReturn(null)
- whenever(mockTaskIdAttributeContainer.task).thenReturn(mockTask)
- whenever(mockTaskIdAttributeContainer.iconView).thenReturn(mockIconView)
- whenever(mockTaskIdAttributeContainer.thumbnailView).thenReturn(mockThumbnailView)
+ whenever(mockTaskContainer.task).thenReturn(mockTask)
+ whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
+ whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView)
whenever(mockTask.getKey()).thenReturn(mockTaskKey)
whenever(mockTaskKey.getId()).thenReturn(taskId)
whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId)
- whenever(mockGroupedTaskView.taskIdAttributeContainers)
- .thenReturn(Array(1) { mockTaskIdAttributeContainer })
+ whenever(mockGroupedTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
val splitAnimInitProps: SplitAnimationController.Companion.SplitAnimInitProps =
splitAnimationController.getFirstAnimInitViews(
{ mockGroupedTaskView },
@@ -200,7 +204,16 @@
doNothing()
.whenever(spySplitAnimationController)
.composeRecentsSplitLaunchAnimatorLegacy(
- any(), any(), any(), any(), any(), any(), any(), any(), any())
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any()
+ )
spySplitAnimationController.playSplitLaunchAnimation(
mockGroupedTaskView,
@@ -219,7 +232,16 @@
verify(spySplitAnimationController)
.composeRecentsSplitLaunchAnimatorLegacy(
- any(), any(), any(), any(), any(), any(), any(), any(), any())
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any()
+ )
}
@Test
@@ -255,6 +277,7 @@
doNothing()
.whenever(spySplitAnimationController)
.composeIconSplitLaunchAnimator(any(), any(), any(), any())
+ doReturn(-1).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
spySplitAnimationController.playSplitLaunchAnimation(
null /* launchingTaskView */,
@@ -276,12 +299,13 @@
}
@Test
- fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarContextCorrectly() {
+ fun playsAppropriateSplitLaunchAnimation_playsIconFullscreenLaunchCorrectly() {
val spySplitAnimationController = spy(splitAnimationController)
- whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+ whenever(mockAppPairIcon.context).thenReturn(mockContextThemeWrapper)
doNothing()
.whenever(spySplitAnimationController)
- .composeScaleUpLaunchAnimation(any(), any(), any())
+ .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), any())
+ doReturn(0).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
spySplitAnimationController.playSplitLaunchAnimation(
null /* launchingTaskView */,
@@ -298,7 +322,62 @@
{} /* finishCallback */
)
- verify(spySplitAnimationController).composeScaleUpLaunchAnimation(any(), any(), any())
+ verify(spySplitAnimationController)
+ .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), eq(0))
+ }
+
+ @Test
+ fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarCMultiWindow() {
+ val spySplitAnimationController = spy(splitAnimationController)
+ whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+ doNothing()
+ .whenever(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), any())
+ doReturn(-1).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
+ spySplitAnimationController.playSplitLaunchAnimation(
+ null /* launchingTaskView */,
+ mockAppPairIcon,
+ taskId,
+ taskId2,
+ null /* apps */,
+ null /* wallpapers */,
+ null /* nonApps */,
+ stateManager,
+ depthController,
+ transitionInfo,
+ transaction,
+ {} /* finishCallback */
+ )
+
+ verify(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), eq(WINDOWING_MODE_MULTI_WINDOW))
+ }
+
+ @Test
+ fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarFullscreen() {
+ val spySplitAnimationController = spy(splitAnimationController)
+ whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+ doNothing()
+ .whenever(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), any())
+ doReturn(0).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
+ spySplitAnimationController.playSplitLaunchAnimation(
+ null /* launchingTaskView */,
+ mockAppPairIcon,
+ taskId,
+ taskId2,
+ null /* apps */,
+ null /* wallpapers */,
+ null /* nonApps */,
+ stateManager,
+ depthController,
+ transitionInfo,
+ transaction,
+ {} /* finishCallback */
+ )
+
+ verify(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), eq(WINDOWING_MODE_FULLSCREEN))
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaplTestsPredictionRow.java b/quickstep/tests/src/com/android/quickstep/util/TaplTestsPredictionRow.java
new file mode 100644
index 0000000..4030b01
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/TaplTestsPredictionRow.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.quickstep.util;
+
+import com.android.quickstep.AbstractQuickStepTest;
+
+import org.junit.Test;
+
+public class TaplTestsPredictionRow extends AbstractQuickStepTest {
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mLauncher.getWorkspace().switchToAllApps();
+ }
+
+ @Test
+ public void testPredictionRow() {
+ mLauncher.getAllApps().getPredictionRowView();
+ }
+}
diff --git a/res/drawable/ic_plus.xml b/res/drawable/ic_plus.xml
index 3ab926a..d004f42 100644
--- a/res/drawable/ic_plus.xml
+++ b/res/drawable/ic_plus.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="19dp"
+ android:width="@dimen/widget_cell_add_button_drawable_width"
android:height="18dp"
android:viewportWidth="19"
android:viewportHeight="18">
diff --git a/res/drawable/ic_private_profile_app_scroller_badge.xml b/res/drawable/ic_private_profile_app_scroller_badge.xml
index b52a277..ede42b9 100644
--- a/res/drawable/ic_private_profile_app_scroller_badge.xml
+++ b/res/drawable/ic_private_profile_app_scroller_badge.xml
@@ -21,8 +21,8 @@
<path
android:pathData="M16.0007 2.66602L5.33398 6.66602V14.786C5.33398 21.5194 9.88065 27.7993 16.0007 29.3327C22.1207 27.7993 26.6673 21.5194 26.6673 14.786V6.66602L16.0007 2.66602ZM20.0007 19.9993V22.666H17.334V23.9993H14.6673V17.1193C12.7473 16.546 11.334 14.786 11.334 12.666C11.334 10.0927 13.4273 7.99935 16.0007 7.99935C18.574 7.99935 20.6673 10.0927 20.6673 12.666C20.6673 14.7727 19.254 16.546 17.334 17.1193V19.9993H20.0007Z"
android:fillType="evenOdd"
- android:fillColor="@android:color/white" />
+ android:fillColor="?android:attr/textColorPrimaryInverse" />
<path
android:pathData="M16 14.666C17.1046 14.666 18 13.7706 18 12.666C18 11.5614 17.1046 10.666 16 10.666C14.8954 10.666 14 11.5614 14 12.666C14 13.7706 14.8954 14.666 16 14.666Z"
- android:fillColor="@android:color/white" />
+ android:fillColor="?android:attr/textColorPrimaryInverse" />
</vector>
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 65f1004..cefe394 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -25,7 +25,9 @@
android:clipToOutline="true"
android:gravity="center_vertical"
android:textDirection="locale"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:contentDescription="@string/ps_container_lock_button_content_description"
+ android:importantForAccessibility="yes">
<LinearLayout
android:id="@+id/settingsAndLockGroup"
@@ -40,7 +42,6 @@
android:layout_width="@dimen/ps_header_image_height"
android:layout_height="@dimen/ps_header_image_height"
android:background="@drawable/ps_settings_background"
- android:layout_marginEnd="@dimen/ps_header_settings_icon_margin_end"
android:src="@drawable/ic_ps_settings"
android:contentDescription="@string/ps_container_settings" />
<LinearLayout
@@ -49,8 +50,8 @@
android:layout_height="@dimen/ps_header_image_height"
android:background="@drawable/ps_lock_background"
android:gravity="center_vertical"
- android:layout_marginEnd="@dimen/ps_header_layout_margin"
- android:contentDescription="@string/ps_container_lock_unlock_button">
+ android:layout_marginEnd="@dimen/ps_lock_button_margin_end"
+ android:contentDescription="@string/ps_container_lock_button_content_description">
<ImageView
android:id="@+id/lock_icon"
android:layout_width="@dimen/ps_lock_icon_size"
@@ -96,6 +97,7 @@
android:gravity="center_vertical"
android:layout_marginStart="@dimen/ps_header_layout_margin"
android:text="@string/ps_container_title"
- android:theme="@style/PrivateSpaceHeaderTextStyle"/>
+ android:theme="@style/PrivateSpaceHeaderTextStyle"
+ android:importantForAccessibility="no"/>
</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 12453a5..b6412db 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -46,20 +46,22 @@
android:layout_gravity="center_vertical"
android:id="@+id/widget_text_container"
android:orientation="vertical">
- <!-- The name of the widget. -->
- <TextView
- android:id="@+id/widget_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:fadingEdge="horizontal"
- android:layout_gravity="center_horizontal"
- android:gravity="center_horizontal|center_vertical"
- android:singleLine="true"
- android:maxLines="1"
- android:textColor="?android:attr/textColorPrimary"
- android:drawablePadding="@dimen/widget_cell_app_icon_padding"
- android:textSize="@dimen/widget_cell_font_size" />
+ <!-- The name of the widget. -->
+ <TextView
+ android:id="@+id/widget_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal|center_vertical"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:textColor="?attr/widgetCellTitleColor"
+ android:textSize="@dimen/widget_cell_title_font_size"
+ android:textFontWeight="@integer/widget_cell_title_font_weight"
+ android:lineHeight="@dimen/widget_cell_title_line_height"
+ android:drawablePadding="@dimen/widget_cell_app_icon_padding" />
<!-- The original dimensions of the widget -->
<TextView
@@ -67,21 +69,23 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/widget_cell_font_size"
- android:alpha="0.7" />
+ android:textColor="?attr/widgetCellSubtitleColor"
+ android:textSize="@dimen/widget_cell_dims_font_size"
+ android:textFontWeight="@integer/widget_cell_dims_font_weight"
+ android:lineHeight="@dimen/widget_cell_dims_line_height" />
<TextView
android:id="@+id/widget_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:textSize="@dimen/widget_cell_font_size"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="2"
+ android:textColor="?attr/widgetCellSubtitleColor"
+ android:textSize="@dimen/widget_cell_description_font_size"
+ android:textFontWeight="@integer/widget_cell_description_font_weight"
+ android:lineHeight="@dimen/widget_cell_description_line_height"
+ android:maxLines="3"
android:ellipsize="end"
- android:fadingEdge="horizontal"
- android:alpha="0.7" />
+ android:fadingEdge="horizontal" />
</LinearLayout>
<Button
@@ -94,12 +98,16 @@
android:paddingEnd="@dimen/widget_cell_add_button_end_padding"
android:text="@string/widget_add_button_label"
android:textColor="?attr/widgetPickerAddButtonTextColor"
- android:textSize="@dimen/widget_cell_font_size"
+ android:textSize="@dimen/widget_cell_add_button_font_size"
+ android:fontWeight="@integer/widget_cell_add_button_font_weight"
+ android:lineHeight="@dimen/widget_cell_add_button_line_height"
android:gravity="center"
android:visibility="gone"
android:drawableStart="@drawable/ic_plus"
- android:drawablePadding="8dp"
+ android:drawablePadding="@dimen/widget_cell_add_button_drawable_padding"
android:drawableTint="?attr/widgetPickerAddButtonTextColor"
+ android:maxLines="1"
+ style="@style/Button.Rounded.Colored"
android:background="@drawable/widget_cell_add_button_background" />
</FrameLayout>
</merge>
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index 065c2ed..0a1407e 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -25,11 +25,10 @@
android:layout_width="@dimen/bottom_sheet_handle_width"
android:layout_height="@dimen/bottom_sheet_handle_height"
android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/bottom_sheet_handle_margin"
+ android:layout_marginBottom="@dimen/widgets_bottom_sheet_handle_margin"
android:visibility="gone"
android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"/>
<TextView
- style="@style/TextHeadline"
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -41,8 +40,13 @@
android:id="@+id/widgets_table_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:fadeScrollbars="false"
- android:layout_marginTop="16dp">
+ android:layout_marginTop="24dp"
+ android:layout_marginBottom="24dp"
+ android:layout_marginHorizontal="@dimen/widget_bottom_sheet_horizontal_margin"
+ android:background="@drawable/widgets_surface_background"
+ android:scrollbarThumbVertical="@drawable/widget_picker_preview_pane_scroll_thumb"
+ android:clipToOutline="true"
+ android:clipChildren="true">
<include layout="@layout/widgets_table_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/widgets_edu.xml b/res/layout/widgets_edu.xml
deleted file mode 100644
index 280c095..0000000
--- a/res/layout/widgets_edu.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.launcher3.views.WidgetsEduView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:gravity="bottom"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/edu_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/bg_rounded_corner_bottom_sheet"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:paddingHorizontal="@dimen/bottom_sheet_edu_padding"
- android:paddingTop="@dimen/bottom_sheet_edu_padding">
-
- <TextView
- style="@style/TextHeadline"
- android:id="@+id/edu_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:text="@string/widget_education_header"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="24sp"
- android:layout_marginBottom="16dp"/>
-
- <TextView
- android:id="@+id/edu_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:text="@string/widget_education_content"
- android:textSize="14sp"
- android:textColor="?android:attr/textColorSecondary"
- android:layout_marginBottom="24dp"/>
-
- <Button
- android:id="@+id/edu_close_button"
- style="@style/Button.Rounded.Colored"
- android:layout_width="match_parent"
- android:layout_height="56dp"
- android:text="@string/widget_education_close_button"
- android:textSize="16sp"
- android:textColor="@color/button_text"
- android:layout_marginBottom="8dp"/>
- </LinearLayout>
-</com.android.launcher3.views.WidgetsEduView>
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 6d26ce3..98f9dac 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -48,8 +48,10 @@
android:layout_gravity="start|center_vertical"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
+ android:textColor="?attr/widgetPickerHeaderAppTitleColor"
+ android:textSize="@dimen/widget_picker_header_app_title_font_size"
+ android:textFontWeight="@integer/widget_picker_header_app_title_font_weight"
+ android:lineHeight="@dimen/widget_picker_header_app_title_line_height"
tools:text="App name" />
<TextView
@@ -58,8 +60,10 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:alpha="0.7"
+ android:textColor="?attr/widgetPickerHeaderAppSubtitleColor"
+ android:textSize="@dimen/widget_picker_header_app_subtitle_font_size"
+ android:textFontWeight="@integer/widget_picker_header_app_subtitle_font_weight"
+ android:lineHeight="@dimen/widget_picker_header_app_subtitle_line_height"
tools:text="m widgets, n shortcuts" />
</LinearLayout>
diff --git a/res/layout/widgets_list_row_header_two_pane.xml b/res/layout/widgets_list_row_header_two_pane.xml
index bdb2aed..d4baf0a 100644
--- a/res/layout/widgets_list_row_header_two_pane.xml
+++ b/res/layout/widgets_list_row_header_two_pane.xml
@@ -51,7 +51,9 @@
android:ellipsize="end"
android:maxLines="1"
android:textColor="?attr/widgetPickerHeaderAppTitleColor"
- android:textSize="16sp"
+ android:textSize="@dimen/widget_picker_header_app_title_font_size"
+ android:textFontWeight="@integer/widget_picker_header_app_title_font_weight"
+ android:lineHeight="@dimen/widget_picker_header_app_title_line_height"
android:duplicateParentState="true"
tools:text="App name" />
@@ -62,7 +64,9 @@
android:ellipsize="end"
android:maxLines="1"
android:textColor="?attr/widgetPickerHeaderAppSubtitleColor"
- android:alpha="0.7"
+ android:textSize="@dimen/widget_picker_header_app_subtitle_font_size"
+ android:textFontWeight="@integer/widget_picker_header_app_subtitle_font_weight"
+ android:lineHeight="@dimen/widget_picker_header_app_subtitle_line_height"
android:duplicateParentState="true"
tools:text="m widgets, n shortcuts" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 7c6aa83..3e63036 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Neem notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Voeg by"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Voeg <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Nuttige inligting binne jou bereik"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Jy kan legstukke by jou tuisskerm voeg om inligting te kry sonder om programme oop te maak"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om legstukinstellings te verander"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Het dit"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Verander legstukinstellings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Deursoek programme"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Laai tans programme …"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tik om op te stel of oop te maak"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privaat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privaat Ruimte-instellings"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Sluit/ontsluit Privaat Ruimte"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privaat, ontsluit."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privaat, gesluit."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Sluit"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Privaat Ruimte-oorgang"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Installeer apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installeer apps in privaat ruimte"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oorvloei"</string>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index fe5b51a..aac898f 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"በጣቶችዎ ጫፎች ላይ ጠቃሚ መረጃ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"መተግበሪያዎችን ሳይከፍቱ መረጃ ለማግኘት በመነሻ ማያ ገጽዎ ላይ ምግብሮችን ማከል ይችላሉ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"የምግብር ቅንብሮችን ለመለወጥ መታ ያድርጉ"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"ገባኝ"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"ለማዋቀር ወይም ለመክፈት መታ ያድርጉ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"የግል"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"የግል ቦታ ቅንብሮች"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"የግል ቦታን ቆልፍ/ክፈት"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"የግል፣ የተከፈተ።"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"የግል፣ የተቆለፈ።"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ቆልፍ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"የግል ቦታ ሽግግር"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"መተግበሪያዎችን ይጫኑ"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"መተግበሪያዎችን ወደ የግል ቦታ ይጫኑ"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ትርፍ ፍሰት"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 7db41c3..103b4cc 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"معلومات مفيدة في متناول يديك"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"للحصول على معلومات بدون فتح التطبيقات، يمكنك إضافة التطبيقات المصغّرة إلى الشاشة الرئيسية."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"انقر لتغيير إعدادات الأداة"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"حسنًا"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"النقر للإعداد أو الفتح"</string>
<string name="ps_container_title" msgid="4391796149519594205">"المساحة الخاصة"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"إعدادات المساحة الخاصة"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل المساحة الخاصة أو فتح قفلها"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"المساحة الخاصة غير مُقفلة."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"المساحة الخاصة مُقفلة."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"قفل"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"النقل إلى المساحة الخاصة"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"تثبيت التطبيقات"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"تثبيت التطبيقات في المساحة الخاصّة"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"القائمة الكاملة"</string>
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 7872e45..2421982 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"আপোনাৰ আঙুলিৰে টিপতে উপযোগী তথ্য পাওক"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"এপ্ নোখোলাকৈ তথ্য পাবলৈ আপুনি নিজৰ গৃহ স্ক্ৰীনত ৱিজেট যোগ দিব পাৰে"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ৱিজেটৰ ছেটিং সলনি কৰিবলৈ টিপক"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"বুজি পালোঁ"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"ছেট আপ কৰিবলৈ টিপক অথবা খোলক"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পে’চৰ ছেটিং"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"প্ৰাইভেট স্পে\'চ লক/আনলক কৰক"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ব্যক্তিগত, আনলক কৰা আছে।"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ব্যক্তিগত, লক কৰা আছে।"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"লক কৰক"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পে’চৰ স্থানান্তৰণ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"এপ্ ইনষ্টল কৰক"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"এপ্সমূহ প্ৰাইভেট স্পেচত ইনষ্টল কৰক"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"অ’ভাৰফ্ল’"</string>
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 0f67a22..9d640a5 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Qeydgötürmə"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Əlavə edin"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidcet əlavə edin"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Faydalı məlumatlar barmaqlarınızın ucunda"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Tətbiqləri açmadan məlumat almaq üçün Əsas ekrana vidcet əlavə edə bilərsiniz"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidcet ayarlarını dəyişmək üçün toxunun"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Anladım"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidcet ayarlarını dəyişin"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tətbiqləri axtarın"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Tətbiqlər yüklənir…"</string>
@@ -188,14 +185,16 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Davam etdirin"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Şəxsi yer"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Məxfi sahə"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Toxunaraq ayarlayın və ya açın"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Şəxsi"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Şəxsi məkan ayarları"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Şəxsi məkanı kilidləyin/kiliddən çıxarın"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Şəxsi, kilidli deyil."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Şəxsi, kilidli."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Kilidləyin"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Şəxsi məkana keçid"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Tətbiqlər quraşdırın"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Tətbiqləri şəxsi sahədə quraşdırın"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kənara çıxma"</string>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 59c4700..0503542 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlozi"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Neophodne aplikacije"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnovno"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Novosti i časopisi"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona za opuštanje"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zabava"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pravljenje beležaka"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajte vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Da biste pronašli informacije bez otvaranja aplikacija, možete da dodate vidžete na početni ekran"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promenili podešavanja vidžeta"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Važi"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promenite podešavanja vidžeta"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste podesili ili otvorili"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Podešavanja privatnog prostora"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključaj/otključaj privatni prostor"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključavanje"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prenos privatnog prostora"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalirajte aplikacije"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliraj aplikacije u privatan prostor"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopno"</string>
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index d4c18f0..b82d97c 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Карысная інфармацыя ў вас пад рукой"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Каб не адкрываць праграмы для прагляду патрэбнай інфармацыі, дадайце віджэты на галоўны экран"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Націсніце, каб змяніць налады віджэта"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Зразумела"</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>
@@ -124,7 +121,7 @@
<string name="allow_rotation_title" msgid="7222049633713050106">"Дазволіць паварот галоўнага экрана"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Значкі апавяшчэнняў"</string>
- <string name="notification_dots_desc_on" msgid="1679848116452218908">"Укл."</string>
+ <string name="notification_dots_desc_on" msgid="1679848116452218908">"Уключана"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Выкл."</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Патрабуецца доступ да апавяшчэнняў"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -188,14 +185,16 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Актываваць"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не ўдалося: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Прыватная вобласць"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Прыватная прастора"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Націсніце, каб наладзіць або адкрыць"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Прыватная"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Налады прыватнай вобласці"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблакіраваць (разблакіраваць) прыватную вобласць"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Прыватная прастора, разблакіравана."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Прыватная прастора, заблакіравана."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Заблакіраваць"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Пераход у прыватную вобласць"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Усталяваць праграмы"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Усталяваць праграмы ў прыватнай прасторы"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дадатковае меню"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 0b92509..517dcf3 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Лесен достъп до полезна информация"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"За да получавате информация, без да отваряте приложенията, можете да добавите приспособления към началния екран"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Докоснете, за да промените настройките на приспособлението"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Разбрах"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Докоснете за настройване или отваряне"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Лично"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Настройки за личното пространство"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заключване/отключване на личното пространство"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Частно, отключено."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Частно, заключено."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Заключване"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Преминаване към личното пространство"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталиране на приложения"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталиране на приложения в частно пространство"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Препълване"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 54238cf..07ea477 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"সহজেই দরকারি তথ্য পান"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"অ্যাপ না খুলেই তথ্য পাওয়ার জন্য, হোম স্ক্রিনে উইজেট যোগ করতে পারবেন"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"উইজেট সেটিংস পরিবর্তন করতে ট্যাপ করুন"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"বুঝেছি"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"সরান"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনস্টল করুন"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"অ্যাপের তথ্য"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ব্যক্তিগত প্রোফাইলে ইনস্টল করুন"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"প্রাইভেট প্রোফাইলে ইনস্টল করুন"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
<string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"সেট-আপ করতে বা খুলতে ট্যাপ করুন"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পেসের সেটিংস"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পেস লক/আনলক করুন"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ব্যক্তিগত, আনলক করা আছে।"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ব্যক্তিগত, লক করা আছে।"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"লক"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পেস ট্রানজিট করা"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"অ্যাপ ইনস্টল করুন"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"প্রাইভেট স্পেসে অ্যাপ ইনস্টল করুন"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ওভারফ্লো"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index d0d4ce6..64710e4 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -65,12 +65,9 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Razgovori"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilješki"</string>
- <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
+ <string name="widget_add_button_label" msgid="2761267068711937179">"Dodajte"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodavanje vidžeta <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Da dobijete informacije bez otvaranja aplikacija, možete dodati vidžete na početni ekran"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da promijenite postavke vidžeta"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Razumijem"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promjena postavki vidžeta"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Inform. o aplikaciji"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u priv. pr."</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u Privatno"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
@@ -188,14 +185,16 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ponovo pokreni"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Privatan prostor"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da postavite ili otvorite"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključaj"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prelazak u privatan prostor"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instaliranje aplikacija"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliranje aplikacija u privatni prostor"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopni meni"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index b57de6b..5c9a411 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -48,7 +48,7 @@
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Notícies i revistes"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"La teva zona de relax"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entreteniment"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Xarxes socials"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salut i fitnes"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Temps"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggeriments per a tu"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Presa de notes"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Afegeix"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Afegeix el widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Informació útil a l\'abast de la mà"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Per obtenir informació sense obrir les aplicacions, pots afegir widgets a la pantalla d\'inici"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca per canviar la configuració del widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Entesos"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Canvia la configuració del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca aplicacions"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"S\'estan carregant les aplicacions…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Toca per configurar o obrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configuració d\'Espai privat"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloqueja o desbloqueja Espai privat"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, desbloquejat."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, bloquejat."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Bloqueja"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Canvia a Espai privat"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instal·la apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instal·la les aplicacions a Espai privat"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú addicional"</string>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index e9fef0c..4c1886d 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Základní"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Nejdůležitější aplikace"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Zprávy a časopisy"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaše klidová zóna"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zábava"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Psaní poznámek"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Přidat"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Přidat widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Užitečné informace na dosah"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Pokud chcete mít informace k dispozici bez otevírání aplikací, můžete si na plochu přidat widgety"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím změníte nastavení widgetu"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Rozumím"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Změnit nastavení widgetu"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hledat v aplikacích"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Načítání aplikací…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Klepnutím nastavíte nebo otevřete"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Soukromé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavení soukromého prostoru"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zamknout/odemknout soukromý prostor"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Soukromé, odemčeno."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Soukromé, uzamčeno."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zamknout"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Převádění soukromého prostoru"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalovat aplikace"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalovat aplikace do soukromého prostoru"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozbalovací nabídka"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 6502e63..5218d34 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notetagning"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Tilføj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tilføj <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-widget"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Nyttige oplysninger lige ved hånden"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Hvis du vil have oplysninger uden at åbne apps, kan du føje widgets til din startskærm"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryk for at ændre widgetindstillinger"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Skift widgetindstillinger"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søg efter apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Indlæser apps…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tryk for at konfigurere eller åbne"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Indstillinger for privat rum"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås/oplås det private område"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, oplåst."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, låst."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Ændringer af tilstanden for det private område"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Installer apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer apps i privat område"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overløb"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 80941c7..1a906c5 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notizen"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Hinzufügen"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ hinzufügen"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Praktische Informationen – immer zur Hand"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Wenn du Informationen erhalten möchtest, ohne Apps zu öffnen, kannst du deinem Startbildschirm Widgets hinzufügen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tippen, um die Widget-Einstellungen zu ändern"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widget-Einstellungen ändern"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps finden"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Apps werden geladen…"</string>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Entfernen"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstallieren"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App-Info"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privat installieren"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Vertraul. installieren"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installieren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"App nicht vorschlagen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vorgeschlagene App fixieren"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Zum Einrichten oder Öffnen tippen"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für privaten Bereich"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaten Bereich sperren/entsperren"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, entsperrt."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, gesperrt."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Sperren"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Sperrzustand des privaten Bereichs wird gerade geändert"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Apps installieren"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Apps im privaten Bereich installieren"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Weitere Optionen"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index a4f8692..ce24675 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Χρήσιμες πληροφορίες στη διάθεσή σας"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Για να λάβετε πληροφορίες χωρίς να ανοίξετε εφαρμογές, μπορείτε να προσθέσετε γραφικά στοιχεία στην αρχική οθόνη."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Πατήστε για αλλαγή των ρυθμίσεων του γραφικού στοιχείου"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Το κατάλαβα"</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>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Πληροφ. εφαρμογής"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Εγκατ. στο απόρρητο"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται η εφαρμογή"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"εγκατάσταση συντομεύσεων"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Πάτημα για ρύθμιση ή άνοιγμα"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Ιδιωτικό"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Ρυθμίσεις Ιδιωτικού χώρου"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Κλείδωμα/Ξεκλείδωμα Ιδιωτικού χώρου"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Ιδιωτικό, ξεκλειδωμένο."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Ιδιωτικό, κλειδωμένο."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Κλείδωμα"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Μετάβαση στον Ιδιωτικό χώρο"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Εγκατάσταση εφαρμογών"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Εγκατάσταση εφαρμογών στον απόρρητο χώρο"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Υπερχείλιση"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 8deac65..d49c479 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index ec69ea8..4a61630 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Got it"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -192,10 +189,11 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+ <string name="ps_add_button_label" msgid="8127988716897128773">"Install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to Private Space"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 8deac65..d49c479 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 8deac65..d49c479 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 476ffda..3a6a1cc 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Got it"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
@@ -192,10 +189,11 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, unlocked."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, locked."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+ <string name="ps_add_button_label" msgid="8127988716897128773">"Install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to Private Space"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 86b0de7..1411bb3 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -48,7 +48,7 @@
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de descanso"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y bienestar"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Clima"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Agregar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Agregar widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Información útil a tu alcance"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Para recibir información de apps sin abrirlas, puedes agregar widgets a la pantalla principal"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Presiona para cambiar la configuración del widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Entendido"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar la configuración del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando apps…"</string>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información de app"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instala en privado"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Presiona para configurar o abrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configuración de Espacio privado"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear o desbloquear Espacio privado"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado (desbloqueado)"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado (bloqueado)"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Bloqueo"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Pasar a Espacio privado"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instala apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instala las apps en el espacio privado"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ampliada"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 971bf81..ff5f2a0 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -48,7 +48,7 @@
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Tu zona de descanso"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y actividad física"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"El tiempo"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Añadir"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Añadir widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Información útil al alcance de la mano"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Para ver información sin abrir una aplicación, puedes añadir widgets a la pantalla de inicio"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar los ajustes del widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Entendido"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar ajustes del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicaciones"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando aplicaciones…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Toca para configurarlo o abrirlo"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Ajustes del espacio privado"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/Desbloquear espacio privado"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado, desbloqueado."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado, bloqueado."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Cambiar a espacio privado"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Descarg. apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Descargar aplicaciones en el espacio privado"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Desplegable"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 46c530e..ca14bed 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Märkmete tegemine"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Lisa"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisa vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Kasulik teave on teie käeulatuses"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Teabe saamiseks rakendusi avamata võite oma avakuvale lisada vidinaid"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Puudutage vidina seadete muutmiseks"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Selge"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidina seadete muutmine"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Otsige rakendusi"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Rakenduste laadimine …"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Seadistamiseks või avamiseks puudutage"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privaatne"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privaatse ruumi seaded"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaatse ruumi lukustamine/avamine"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privaatne, võrgulukuta."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privaatne, lukustatud."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lukk"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Privaatse ruumi üleviimine"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Rakenduste installimine"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Rakenduste installimine privaatses ruumis"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ületäide"</string>
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index acf67f2..538824f 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Oharrak idazteko"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Gehitu"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Gehitu <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Informazio erabilgarria beti eskura"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Aplikaziorik ireki beharrik gabe informazioa zuzenean jasotzeko, gehitu widgetak orri nagusian"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Sakatu hau widgeten ezarpenak aldatzeko"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Ados"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Aldatu widgeten ezarpenak"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Bilatu aplikazioetan"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikazioak kargatzen…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Sakatu konfiguratzeko edo irekitzeko"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Pribatua"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Eremu pribatuaren ezarpenak"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blokeatu/Desblokeatu eremu pribatua"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Pribatua, desblokeatuta."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Pribatua, blokeatuta."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Blokeatu"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Eremu pribaturako trantsizioa"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalatu aplikazioak"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalatu aplikazioak eremu pribatuan"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Luzapena"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 163739a..7036efb 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"دسترسی آسان به اطلاعات سودمند"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"با افزودن ابزارکها به صفحه اصلی میتوانید اطلاعات را بدون باز کردن برنامهها دریافت کنید"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزارک، ضربه بزنید"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"متوجهام"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"برای راهاندازی یا باز کردن، ضربه بزنید"</string>
<string name="ps_container_title" msgid="4391796149519594205">"خصوصی"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"تنظیمات «فضای خصوصی»"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل/ باز کردن «فضای خصوصی»"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"خصوصی، باز."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"خصوصی، قفل."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"قفل کردن"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"انتقال «فضای خصوصی»"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"نصب برنامهها"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"نصب برنامهها در «فضای خصوصی»"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"سرریز"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 9cb07fb..5f26348 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Muistiinpanojen tekeminen"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Lisää"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisää widget: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Hyödyllisiä tietoja käden ulottuvilla"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Jos haluat nähdä tietoja avaamatta sovelluksia, voit lisätä aloitusnäytölle widgetejä"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Napauta, niin voit muuttaa widgetin asetuksia"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Muuta widgetin asetuksia"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hae sovelluksia"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Ladataan sovelluksia…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Ota käyttöön tai avaa napauttamalla"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Yksityinen"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Yksityisen tilan asetukset"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lukitse yksityinen tila / avaa sen lukitus"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Yksityinen, lukitsematon."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Yksityinen, lukittu."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lukko"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Yksityisen tilan siirtäminen"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Asenna sovelluksia"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Asenna sovelluksia yksityiseen tilaan"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ylivuoto"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 0254d5e..f5c580e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de note"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Renseignements utiles à portée de main"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Pour obtenir des informations sans ouvrir d\'applications, vous pouvez ajouter des widgets à votre écran d\'accueil"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Touchez pour modifier les paramètres du widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifier les paramètres du widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications en cours…"</string>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Détails de l\'appli"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer dans privé"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'application"</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="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
@@ -189,13 +186,15 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrer"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Toucher pour configurer ou ouvrir"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Touchez pour configurer ou ouvrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Paramètres de l\'Espace privé"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller l\'Espace privé"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privé, déverrouillé."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privé, verrouillé."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Verrouiller"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transition vers l\'Espace privé"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Installer des applications"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer des applications dans l\'Espace privé"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu à développer"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 1329a16..abc2d2b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Les bases"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Indispensables"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Actualités et magazines"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Votre espace détente"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Divertissement"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de notes"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez un widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Infos utiles à portée de main"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Pour obtenir des infos sans ouvrir d\'applis, vous pouvez ajouter des widgets à votre écran d\'accueil"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Appuyez pour modifier les paramètres du widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifier les paramètres du widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications…"</string>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Infos sur l\'appli"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer en mode privé"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'application"</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="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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Appuyer pour ouvrir ou configurer"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Paramètres d\'Espace privé"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller Espace privé"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privé, déverrouillé"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privé, verrouillé"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Verrouiller"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transition vers Espace privé"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Installer applis"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer des applis dans l\'espace privé"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dépassement"</string>
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 4466c6d..fc3c087 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Engadir"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Engadir o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Información útil ao teu alcance"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Se queres obter información sen abrir as aplicacións, podes engadir widgets á pantalla de inicio"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar a configuración do widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Entendido"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Cambiar configuración do widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicacións"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando aplicacións…"</string>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información da app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir aplicación"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Toca para configuralo ou abrilo"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configuración do espazo privado"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear ou desbloquear o espazo privado"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado, desbloqueado."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado, bloqueado."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transición ao espazo privado"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalar as aplicacións no espazo privado"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú adicional"</string>
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 931c38a..a21c6b3 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ઉપયોગી માહિતી તમારી આંગળીના ટેરવે"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ઍપને ખોલ્યા વિના માહિતી મેળવવા માટે, તમે તમારી હોમ સ્ક્રીનમાં વિજેટ ઉમેરી શકો છો"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"વિજેટના સેટિંગ બદલવા માટે ટૅપ કરો"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"સમજાઈ ગયું"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"સેટઅપ કરવા કે ખોલવા માટે ટૅપ કરો"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ખાનગી"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ખાનગી સ્પેસના સેટિંગ"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ખાનગી સ્પેસને લૉક/અનલૉક કરો"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ખાનગી સ્પેસ, અનલૉક કરેલી છે."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ખાનગી સ્પેસ, લૉક કરેલી છે."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"લૉક"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ખાનગી સ્પેસ પર સ્થાનાંતરણ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ઍપ ઇન્સ્ટૉલ કરો"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ખાનગી સ્પેસમાં ઍપ ઇન્સ્ટૉલ કરો"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ઓવરફ્લો"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 600cde4..963dcce 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"काम की जानकारी आसानी से पाएं"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ऐप्लिकेशन को खोले बिना उनकी जानकारी पाने के लिए, होम स्क्रीन पर विजेट जोड़े जा सकते हैं"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट की सेटिंग में बदलाव करने के लिए टैप करें"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"ठीक है"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"सेट अप करने या खोलने के लिए टैप करें"</string>
<string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"प्राइवेट स्पेस सेटिंग"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"प्राइवेट स्पेस को लॉक करें/अनलॉक करें"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"प्राइवेट स्पेस को अनलॉक किया गया."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"प्राइवेट स्पेस को लॉक किया गया."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"लॉक"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"प्राइवेट स्पेस की सेटिंग में बदलाव किया जा रहा है"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ऐप्लिकेशन इंस्टॉल करें"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"प्राइवेट स्पेस में ऐप्लिकेशन इंस्टॉल करें"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओवरफ़्लो"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index e860ea9..d66ddda 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilježaka"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Da biste dobili informacije bez otvaranja aplikacija, možete dodati widgete na početni zaslon"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promijenili postavke widgeta"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Shvaćam"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promijenite postavke widgeta"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretraži aplikacije"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Učitavanje aplikacija…"</string>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliranje u privatni profil"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u privatno"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prikvači predviđenu apl."</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste postavili ili otvorili"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključavanje"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prelazak na privatni prostor"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalirajte aplikacije"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliranje aplikacija u privatni prostor"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dodatni izbornik"</string>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 03a30c4..64cf0f2 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Jegyzetelés"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Hozzáadás"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadása"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Hasznos információk egy koppintásnyira"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Ha az alkalmazások megnyitása nélkül szeretne információhoz jutni, felvehet modulokat a kezdőképernyőre"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ide koppintva módosíthatja a modulbeállításokat"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Értem"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"A modulbeállítások módosítása"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Alkalmazások keresése"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Alkalmazások betöltése…"</string>
@@ -89,9 +86,9 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Törlés"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Eltávolítás"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Alkalmazásinfó"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Telepítés privátra"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privát telepítés"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon alkalmazást"</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="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>
@@ -190,12 +187,14 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Koppintson a beállításhoz vagy a megnyitáshoz"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Privát"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Magánterület"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privát terület beállításai"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privát terület zárolása/zárolásának feloldása"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privát, feloldott."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privát, zárolt."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zárolás"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Átállás privát területre…"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"App telepítése"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Alkalmazások telepítése magánterületre"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Túlcsordulás"</string>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 0f65295..0c2e4ff 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Բոլոր կարևոր տեղեկությունները՝ ձեռքի տակ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Ավելացրեք վիջեթներ ձեր հիմնական էկրանին, որպեսզի տեղեկություններ ստանաք՝ առանց հավելվածները բացելու։"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Հպեք՝ վիջեթի կարգավորումները փոփոխելու համար"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Եղավ"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Հեռացնել"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ապատեղադրել"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Հավելվածի մասին"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Տեղադրել անձնականում"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Տեղադրել մասնավորում"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Հպեք կարգավորելու կամ բացելու համար"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Մասնավոր"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Անձնական տարածքի կարգավորումներ"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Կողպել/ապակողպել մասնավոր տարածքը"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Անձնական, ապակողպված է։"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Անձնական, կողպված է։"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Կողպում"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Անցում մասնավոր տարածք"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Հավելվածների տեղադրում"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Հավելվածների տեղադրում անձնական տարածքում"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Լրացուցիչ ընտրացանկ"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index c678e41..b40e6c7 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pembuatan catatan"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Tambahkan"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Info bermanfaat mudah dilihat"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Untuk mendapatkan info tanpa membuka aplikasi, Anda dapat menambahkan widget ke layar utama"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketuk untuk mengubah setelan widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Oke"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ubah setelan widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Telusuri aplikasi"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Memuat aplikasi…"</string>
@@ -89,9 +86,9 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Hapus"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info aplikasi"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal secara pribadi"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal di ruang privasi"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan aplikasi"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</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>
@@ -188,14 +185,16 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Aktifkan lagi"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Ruang pribadi"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Ketuk untuk menyiapkan atau membuka"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Pribadi"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Privasi"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Setelan Ruang Pribadi"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka Kunci Ruang Pribadi"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Pribadi, tidak terkunci."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Pribadi, dikunci."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Kunci"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Ruang Pribadi Bertransisi"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instal aplikasi"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instal aplikasi ke Ruang Pribadi"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu tambahan"</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 73a7d64..d80a333 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Glósugerð"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Bæta við"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Bæta græjunni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> við"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Gagnlegar upplýsingar innan seilingar"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Þú getur bætt við græjum á heimaskjáinn til að fá upplýsingar án þess að opna forrit"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ýttu til að breyta græjustillingum"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Ég skil"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Breyta græjustillingum"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Leita í forritum"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Hleður forrit…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Ýttu til að setja upp eða opna"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Lokað"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Læsa leynirými/taka leynirými úr lás"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Lokað, ólæst."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Lokað, læst."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Læsa"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Einkarými að breytast"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Setja upp forrit"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Setja upp forrit í leynirými"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Yfirflæði"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index c32fec0..cb6e30a 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Aggiunta di note"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Aggiungi"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Aggiungi widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Informazioni utili a portata di mano"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Per ricevere informazioni senza aprire le app, puoi aggiungere dei widget alla schermata Home"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tocca per modificare le impostazioni del widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifica le impostazioni del widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca nelle app"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Caricamento delle app…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tocca per configurare o aprire"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privato"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Impostazioni dello Spazio privato"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blocca/sblocca Spazio privato"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privato, sbloccato."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privato, bloccato."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Blocca"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transizione dello Spazio privato in corso…"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Installa app"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installa le app su spazi privati"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Extra"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 88dce21..acd91f0 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"הוספה למסך הבית"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g> נוסף למסך הבית"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"הצעות"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"האפליקציות שחייבים להכיר"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"הכי חשוב"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"חדשות וכתבי עת"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"המקום שלך לרגיעה"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"בידור"</string>
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"קבלת מידע שימושי בהקשה"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"רוצה לקבל מידע בלי לפתוח אפליקציות? אפשר להוסיף ווידג\'טים למסך הבית"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"אפשר לשנות את הגדרות הווידג\'ט בהקשה"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"הבנתי"</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>
@@ -189,13 +186,15 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"סינון"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"מרחב פרטי"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"אפשר להקיש כדי להגדיר או לפתוח"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"יש להקיש כדי להגדיר או לפתוח"</string>
<string name="ps_container_title" msgid="4391796149519594205">"פרטי"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"הגדרות המרחב הפרטי"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"נעילה או ביטול הנעילה של המרחב הפרטי"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"פרטי, פתוח."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"פרטי, נעול."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"נעילה"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"מעבר למרחב הפרטי"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"התקנת אפליקציות"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"התקנת אפליקציות במרחב הפרטי"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"אפשרויות נוספות"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index d028e4e..b672566 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ウィジェットで情報を得る"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ホーム画面にウィジェットを追加すると、アプリを開かずに情報を入手できます"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"タップしてウィジェットの設定を変更する"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"設定したり開いたりするにはタップしてください"</string>
<string name="ps_container_title" msgid="4391796149519594205">"プライベート"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"プライベート スペースの設定"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"プライベート スペースをロック / ロック解除する"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"非公開で、ロックが解除されています。"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"非公開で、ロックされています。"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ロック"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"プライベート スペース移行中"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"アプリをインストールする"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"プライベート スペースにアプリをインストールします"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"オーバーフロー"</string>
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index e3b5627..3c94fcf 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ადვილად მისაწვდომი სასარგებლო ინფორმაცია"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"იმისთვის, რომ ინფორმაცია აპების გაუხსნელად მიიღოთ, შეგიძლიათ, მთავარ ეკრანზე ვიჯეტები დაამატოთ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"შეეხეთ ვიჯეტის პარამეტრების შესაცვლელად"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"გასაგებია"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"ამოშლა"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"დეინსტალაცია"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"აპის შესახებ"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"პირადში ინსტალაცია"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"კერძოში ინსტალაცია"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"დასაყენებლად ან გასახსნელად შეეხეთ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"პირადი"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"პირადი სივრცის პარამეტრები"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"პირადი სივრცის ჩაკეტვა/განბლოკვა"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"პირადი (განბლოკილი)."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"პირადი (ჩაკეტილი)."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ჩაკეტვა"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"პირად სივრცეზე გადასვლა"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"აპების ინსტალაცია"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"კერძო სივრცეში აპების ინსტალაცია"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"გადავსება"</string>
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 215ac74..7853973 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Саусақпен түртсеңіз болғаны – пайдалы ақпарат көз алдыңызда"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Қолданбаларды ашпай-ақ ақпарат алу үшін негізгі экранға тиісті виджеттерді қосыңыз."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджет параметрлерін өзгерту үшін түртіңіз."</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Түсінікті"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Алып тастау"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Қолданба ақпараты"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Жеке профильге орнату"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Құпия профильге орнату"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Болжанған қолданбаны бекіту"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Реттеу немесе ашу үшін түртіңіз"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Жеке бөлме параметрлері"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке бөлмені құлыптау/оның құлпын ашу"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Құпия (құлыпталмаған)."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Құпия (құлыптаулы)."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Құлыптау"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Жеке бөлмеге өту"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Қолданбалар орнату"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Қолданбаларды \"Құпия кеңістікке\" орнатыңыз."</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Қосымша мәзір"</string>
</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 243f9f4..6113d51 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ទទួលបានព័ត៌មានដែលមានប្រយោជន៍យ៉ាងងាយស្រួល"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ដើម្បីទទួលបានព័ត៌មានដោយមិនចាំបាច់បើកកម្មវិធី អ្នកអាចបញ្ចូលធាតុក្រាហ្វិកទៅក្នុងអេក្រង់ដើមរបស់អ្នក"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ចុចដើម្បីប្ដូរការកំណត់ធាតុក្រាហ្វិក"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"យល់ហើយ"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"ចុចដើម្បីរៀបចំ ឬបើក"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ឯកជន"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ការកំណត់ Private Space"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ចាក់សោ/ដោះសោ Private Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ឯកជន បានដោះសោ។"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ឯកជន ជាប់សោ។"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ចាក់សោ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ការផ្លាស់ប្ដូរ Private Space"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ដំឡើងកម្មវិធី"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ដំឡើងកម្មវិធីទៅលំហឯកជន"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ម៉ឺនុយបន្ថែម"</string>
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 4ab4ada..0cce0c4 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ನಿಮ್ಮ ಬೆರಳ ತುದಿಯಲ್ಲಿ ಉಪಯುಕ್ತ ಮಾಹಿತಿ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ಆ್ಯಪ್ಗಳನ್ನು ತೆರೆಯದೆಯೇ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು, ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ನೀವು ವಿಜೆಟ್ಗಳನ್ನು ಸೇರಿಸಬಹುದು"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"ಅರ್ಥವಾಯಿತು"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"ಸೆಟಪ್ ಮಾಡಲು ಅಥವಾ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ಖಾಸಗಿ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಅನ್ನು ಲಾಕ್/ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ಖಾಸಗಿ, ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ಖಾಸಗಿ, ಲಾಕ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ಲಾಕ್ ಮಾಡಿ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಪರಿವರ್ತನೆಯಾಗುತ್ತಿದೆ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ಆ್ಯಪ್ಗಳನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರೈವೇಟ್ ಸ್ಪೇಸ್ನಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ಓವರ್ಫ್ಲೋ"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 42b12ab..6850b2b 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"빠르게 유용한 정보 확인"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"앱을 열지 않고 정보를 확인하려면 홈 화면에 위젯을 추가하세요."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"탭하여 위젯 설정 변경"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"확인"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"삭제"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"제거"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"앱 정보"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"비공개 설치"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"비공개 스페이스에 설치"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
<string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"탭하여 설정 또는 열기"</string>
<string name="ps_container_title" msgid="4391796149519594205">"비공개"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"비공개 스페이스 설정"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"비공개 스페이스 잠금/잠금 해제"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"비공개, 잠금 해제됨."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"비공개, 잠김."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"잠금"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"비공개 스페이스 전환"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"앱 설치"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"비공개 스페이스에 앱 설치"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"오버플로"</string>
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index f908299..4d4c1a6 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Керектүү маалымат манжаңыздын учунда"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Бир нерсе билүү үчүн колдонмолорду улам ачып убара болбостон, башкы экранга виджеттерди кошуп коюңуз."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджеттин параметрлерин өзгөртүү үчүн таптап коюңуз"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Түшүндүм"</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>
@@ -189,13 +186,15 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Чыпкалоо"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Аткарылган жок: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Жеке мейкиндик"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Тууралоо же ачуу үчүн таптап коюңуз"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Тууралоо же ачуу үчүн тийип коюңуз"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Жеке мейкиндиктин параметрлери"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке мейкиндикти кулпулоо/кулпусун ачуу"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Купуя, кулпусу ачык."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Купуя, кулпуланган."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Кулпулоо"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Жеке чөйрөгө өтүү"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Колдонмолорду орнотуу"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Колдонмолорду Жеке мейкиндикке орнотуe"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Кошумча меню"</string>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index c215bc8..27476d2 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ຂໍ້ມູນທີ່ເປັນປະໂຫຍດຢູ່ປາຍນິ້ວຂອງທ່ານ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ເພື່ອຮັບຂໍ້ມູນໂດຍບໍ່ຕ້ອງເປີດແອັບ, ທ່ານສາມາດເພີ່ມວິດເຈັດໃສ່ໂຮມສະກຣີນຂອງທ່ານໄດ້"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ແຕະເພື່ອປ່ຽນການຕັ້ງຄ່າວິດເຈັດ"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"ເຂົ້າໃຈແລ້ວ"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"ແຕະເພື່ອຕັ້ງຄ່າ ຫຼື ເປີດ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ສ່ວນຕົວ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ການຕັ້ງຄ່າພື້ນທີ່ສ່ວນຕົວ"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ລັອກ/ປົດລັອກພື້ນທີ່ສ່ວນຕົວ"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ສ່ວນຕົວ, ປົດລັອກແລ້ວ."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ສ່ວນຕົວ, ລັອກແລ້ວ."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ລັອກ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ການປ່ຽນແປງພື້ນທີ່ສ່ວນຕົວ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ຕິດຕັ້ງແອັບ"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ຕິດຕັ້ງແອັບໄປໃສ່ພື້ນທີ່ສ່ວນບຸກຄົນ"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ການດຳເນີນການເພີ່ມເຕີມ"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index fda9e95..2d101fd 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Užrašų kūrimas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Pridėti"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridėti valdiklį: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Lengvai pasiekiama naudinga informacija"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Jei norite gauti informacijos neatidarę programų, galite pridėti valdiklių pagrindiniame ekrane"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Palieskite, kad pakeistumėte valdiklio nustatymus"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Supratau"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Pakeisti valdiklio nustatymus"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Paieškos programos"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Įkeliamos programos…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Palieskite, kad nustatytumėte arba atidarytumėte"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privatus"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privačios erdvės nustatymai"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Užrakinti ir (arba) atrakinti privačią erdvę"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatus, atrakintas."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatus, užrakintas."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Užrakinti"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Privačios erdvės perkėlimas"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Programų diegimas"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Įdiegti programas privačioje erdvėje"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Perpildymas"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index c9c4dfa..587bda4 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Piezīmju pierakstīšana"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Pievienot"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pievienot logrīku <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Ērta piekļuve noderīgai informācijai"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Lai iegūtu informāciju, neatverot lietotnes, varat pievienot sākuma ekrānam logrīkus"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Pieskarieties, lai mainītu logrīka iestatījumus."</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Labi"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Mainīt logrīka iestatījumus"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Meklēt lietotnes"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Notiek lietotņu ielāde…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Pieskarieties, lai iestatītu vai atvērtu"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privātā mape"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privātās mapes iestatījumi"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloķēt/atbloķēt privāto mapi"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privāta un nav bloķēta."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privāta un bloķēta."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Bloķēšana"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Pāriet uz privāto mapi"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Lietotņu instalēšana"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalējiet lietotnes privātajā telpā."</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Pārpilde"</string>
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index a429c7a..1dc7e15 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Корисни информации на дофат на прстите"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"За да добивате информации без да ги отворате апликациите, може да додадете виџети на почетниот екран"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Допрете за да ги промените поставките за виџетот"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Сфатив"</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>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Инф. за апликација"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. во приватен"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апликација"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање кратенки"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
@@ -130,7 +127,7 @@
<string name="msg_missing_notification_access" msgid="281113995110910548">"За да се прикажуваат „Точки за известување“, вклучете ги известувањата за апликацијата <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Промени ги поставките"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"Прикажувај точки за известување"</string>
- <string name="developer_options_title" msgid="700788437593726194">"Опции за програмери"</string>
+ <string name="developer_options_title" msgid="700788437593726194">"Програмерски опции"</string>
<string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Додавај икони за апликации на почетниот екран"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нови апликации"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Допрете за да поставите или отворите"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Приватен простор"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Поставки за „Приватен простор“"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заклучување/отклучување на „Приватен простор“"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Приватно, отклучено."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Приватно, заклучено."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Заклучи"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Префрлање на „Приватен простор“"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталирајте апликации"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталирање апликации во „Приватен простор“"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Проширено балонче"</string>
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index e3b6e6b..db74218 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ഉപകാരപ്രദമായ വിവരങ്ങൾ നിങ്ങളുടെ വിരൽത്തുമ്പിൽ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ആപ്പുകൾ തുറക്കാതെ വിവരങ്ങൾ ലഭിക്കാൻ, നിങ്ങൾക്ക് ഹോം സ്ക്രീനിലേക്ക് വിജറ്റുകൾ ചേർക്കാം"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"വിജറ്റ് ക്രമീകരണം മാറ്റാൻ ടാപ്പ് ചെയ്യുക"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"മനസ്സിലായി"</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>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"ആപ്പ് വിവരങ്ങൾ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"സ്വകാര്യമായി ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കരുത്"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
<string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"സജ്ജീകരിക്കാനോ തുറക്കാനോ ടാപ്പ് ചെയ്യുക"</string>
<string name="ps_container_title" msgid="4391796149519594205">"സ്വകാര്യം"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"സ്വകാര്യ സ്പേസ് ക്രമീകരണം"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"സ്വകാര്യ സ്പേസ് ലോക്ക് ചെയ്യുക/അൺലോക്ക് ചെയ്യുക"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"സ്വകാര്യം, അൺലോക്ക് ചെയ്തിരിക്കുന്നു."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"സ്വകാര്യം, ലോക്ക് ചെയ്തു."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ലോക്ക് ചെയ്യുക"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"പ്രൈവറ്റ് സ്പേസ് ട്രാൻസിഷനിംഗ്"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"സ്വകാര്യ സ്പേസിലേക്ക് ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ഓവർഫ്ലോ"</string>
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index ffc6509..dba38c9 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Хэрэгтэй мэдээллээ хурууныхаа үзүүрээр аваарай"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Аппуудыг нээлгүйгээр мэдээлэл авахын тулд та үндсэн нүүрэндээ виджетүүд нэмэх боломжтой"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Жижиг хэрэгслийн тохиргоог өөрчлөхийн тулд товшино уу"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Ойлголоо"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Тохируулах эсвэл нээхийн тулд товших"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Хувийн"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space-н тохиргоо"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Private Space-г түгжих/түгжээг тайлах"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Хувийн, түгжээг тайлсан."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Хувийн, түгжээтэй."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Түгжээ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space-н шилжилт"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Аппуудыг суулгах"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Хувийн орон зайд аппууд суулгана уу"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Урт цэс"</string>
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index c8af44e..29aa20d 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"तुमच्यासाठी सहज उपलब्ध असलेली माहिती"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ॲप्स न उघडता माहिती मिळवण्यासाठी, तुम्ही तुमच्या होम स्क्रीनवर विजेट जोडू शकता"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट सेटिंग्ज बदलण्यासाठी टॅप करा"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"समजले"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"सेट करण्यासाठी किंवा उघडण्यासाठी टॅप करा"</string>
<string name="ps_container_title" msgid="4391796149519594205">"खाजगी"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"खाजगी स्पेस ची सेटिंग्ज"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"खाजगी स्पेस लॉक/अनलॉक करा"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"खाजगी, अनलॉक केलेली."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"खाजगी, लॉक केलेली."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"लॉक"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"खाजगी स्पेस वर स्विच करणे"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"अॅप्स इंस्टॉल करा"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"अॅप्स खाजगी स्पेस मध्ये इंस्टॉल करा"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओव्हरफ्लो"</string>
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 68a9238..58de46c 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan pada skrin utama"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan pada skrin utama"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Cadangan"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Apl Asas"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Penting"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Berita & majalah"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zon Santai Anda"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hiburan"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pengambilan nota"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Tambah"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Maklumat berguna di hujung jari anda"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Untuk mendapatkan maklumat tanpa membuka apl, anda boleh menambahkan widget pada skrin utama anda"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketik untuk menukar tetapan widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Tukar tetapan widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cari apl"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Memuatkan apl…"</string>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Alih keluar"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Maklumat apl"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pasang dalam peribadi"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pasang dalam persendirian"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan cadangkan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Sematkan Ramalan"</string>
@@ -190,12 +187,14 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Ketik untuk menyediakan atau membuka"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Peribadi"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Persendirian"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Tetapan Ruang Peribadi"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka kunci Ruang Peribadi"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Peribadi, tidak berkunci."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Peribadi, dikunci."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Kunci"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Peralihan Ruang Peribadi"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Pasang apl"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Pasang apl pada Ruang Peribadi"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Limpahan"</string>
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index aca6d7d..0b3ab36 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"အသုံးဝင်သော အချက်အလက်များကို အလွယ်တကူ ရယူလိုက်ပါ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"အက်ပ်မဖွင့်ဘဲ အချက်အလက်များရယူရန် ပင်မစာမျက်နှာတွင် ဝိဂျက်များ ထည့်နိုင်သည်"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ဝိဂျက် ဆက်တင်များကို ပြောင်းရန် တို့ပါ"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"နားလည်ပြီ"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"စနစ်ထည့်သွင်းရန် (သို့) ဖွင့်ရန် တို့ပါ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"သီးသန့်"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"သီးသန့်ချတ်ခန်း ဆက်တင်များ"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"သီးသန့်ချတ်ခန်း လော့ခ်ချ/ဖွင့်ရန်"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"သီးသန့် လော့ခ်ဖွင့်ထားသည်။"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"သီးသန့် လော့ခ်ချထားသည်။"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"လော့ခ်ချခြင်း"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"သီးသန့်ချတ်ခန်း အပြောင်းအလဲ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"အက်ပ်ထည့်ခြင်း"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"‘သီးသန့်နေရာ’ တွင် အက်ပ်များ ထည့်သွင်းနိုင်သည်"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"မီနူးအပို"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 3f82cb3..0ca4380 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notatskriving"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Legg til"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Legg til <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Lett tilgjengelig nyttig informasjon"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"For å se informasjon uten å åpne apper kan du legge til moduler på startskjermen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trykk for å endre modulinnstillinger"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Greit"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Endre modulinnstillinger"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søk etter apper"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Laster inn appene …"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Trykk for å konfigurere eller åpne"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Innstillinger for Private Space"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås / lås opp Private Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat (ulåst)."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat (låst)."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space-overgang"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Installer apper"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer apper i privat område"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflyt"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 8e06879..6b958b5 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"उपयोगी जानकारी सजिलै प्राप्त गर्नुहोस्"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"एपहरू नखोलिकनै जानकारी प्राप्त गर्न तपाईं आफ्नो होम स्क्रिनमा विजेटहरू हाल्न सक्नुहुन्छ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेटका सेटिङ बदल्न ट्याप गर्नुहोस्"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"बुझेँ"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"सेटअप गर्न वा खोल्न ट्याप गर्नुहोस्"</string>
<string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"निजी स्पेससम्बन्धी सेटिङ"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"निजी स्पेस लक/अनलक गर्नुहोस्"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"निजी, अनलक गरिएको।"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"निजी, लक गरिएको।"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"लक गर्नुहोस्"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"निजी स्पेस ट्रान्जिसन गरिँदै छ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"एपहरू इन्स्टल गर्नुहोस्"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"निजी स्पेसमा एपहरू इन्स्टल गर्नुहोस्"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओभरफ्लो"</string>
</resources>
diff --git a/res/values-night-v34/colors.xml b/res/values-night-v34/colors.xml
new file mode 100644
index 0000000..af28119
--- /dev/null
+++ b/res/values-night-v34/colors.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <color name="widget_picker_secondary_surface_color_dark">
+ @android:color/system_surface_bright_dark</color>
+ <color name="widget_picker_header_app_title_color_dark">
+ @android:color/system_on_surface_dark</color>
+ <color name="widget_picker_header_app_subtitle_color_dark">
+ @android:color/system_on_surface_variant_dark</color>
+ <color name="widget_cell_title_color_dark">
+ @android:color/system_on_surface_dark</color>
+ <color name="widget_cell_subtitle_color_dark">
+ @android:color/system_on_surface_variant_dark</color>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 3da759f..65bd267 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Aantekeningen maken"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Toevoegen"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toevoegen"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Nuttige informatie binnen handbereik"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Als je informatie wilt krijgen zonder apps te openen, kun je widgets toevoegen aan je startscherm"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om de widgetinstellingen te wijzigen"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widgetinstellingen wijzigen"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps zoeken"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Apps laden…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tik om in te stellen of te openen"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Instellingen voor privéruimte"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privéruimte vergrendelen/ontgrendelen"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privé, niet vergrendeld."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privé, vergrendeld."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Vergrendelen"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Overschakelen naar privéruimte"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Apps installeren"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Apps installeren in privégedeelte"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overloop"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index d83a02b..1dc7247 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ଉପଯୋଗୀ ସୂଚନା ଆପଣଙ୍କ ପାଖରେ ସହଜରେ ଉପଲବ୍ଧ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ଆପ୍ସକୁ ନଖୋଲି ସୂଚନା ପାଇବା ପାଇଁ, ଆପଣ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନରେ ୱିଜେଟଗୁଡ଼ିକୁ ଯୋଗ କରିପାରିବେ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"ବୁଝିଗଲି"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"ସେଟ ଅପ କରିବା କିମ୍ବା ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ପ୍ରାଇଭେଟ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ପ୍ରାଇଭେଟ ସ୍ପେସ ସେଟିଂସ"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଲକ/ଅନଲକ କରନ୍ତୁ"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ପ୍ରାଇଭେଟ, ଅନଲକ କରାଯାଇଛି।"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ପ୍ରାଇଭେଟ, ଲକ କରାଯାଇଛି।"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ଲକ କରନ୍ତୁ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ପ୍ରାଇଭେଟ ସ୍ପେସ ଟ୍ରାଞ୍ଜିସନିଂ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ଆପ୍ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ଆପ୍ସକୁ ପ୍ରାଇଭେଟ ସ୍ପେସରେ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ଓଭରଫ୍ଲୋ"</string>
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index fa01494..1e145ea 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ਮਹੱਤਵਪੂਰਨ ਜਾਣਕਾਰੀ ਤੁਰੰਤ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ਐਪਾਂ ਨੂੰ ਖੋਲ੍ਹੇ ਬਿਨਾਂ ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, ਤੁਸੀਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ਵਿਜੇਟ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"ਸਮਝ ਲਿਆ"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"ਸੈੱਟਅੱਪ ਕਰਨ ਜਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ਨਿੱਜੀ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ਨਿੱਜੀ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਲਾਕ/ਅਣਲਾਕ ਕਰੋ"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ਨਿੱਜੀ, ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ।"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ਨਿੱਜੀ, ਲਾਕ ਕੀਤਾ ਗਿਆ।"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ਲਾਕ ਕਰੋ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ਐਪਾਂ ਸਥਾਪਤ ਕਰੋ"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਵਿੱਚ ਐਪਾਂ ਸਥਾਪਤ ਕਰੋ"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ਓਵਰਫ਼ਲੋ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 18642d7..b781314 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestie"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Niezbędne"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Najbardziej przydatne"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Wiadomości i czasopisma"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Strefa relaksu"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Rozrywka"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notatki"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Użyteczne informacje w zasięgu ręki"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Możesz dodać widżety do ekranu głównego, aby uzyskiwać informacje bez otwierania aplikacji"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Kliknij, aby zmienić ustawienia widżetu"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Zmień ustawienia widżetu"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Wyszukaj aplikacje"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Ładuję aplikacje…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Kliknij, aby skonfigurować lub otworzyć"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Prywatne"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Ustawienia obszaru prywatnego"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zablokuj/odblokuj obszar prywatny"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Prywatna, bez blokady."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Prywatna, zablokowana."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zablokuj"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Przenoszenie obszaru prywatnego"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instaluj aplikacje"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Zainstaluj aplikacje w przestrzeni prywatnej"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozwiń menu"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 6d5c699..1783b05 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicione o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Informações úteis à sua disposição"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Para obter informações sem abrir apps, pode adicionar widgets ao seu ecrã principal"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para alterar as definições do widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Alterar definições do widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"A carregar aplicações…"</string>
@@ -189,13 +186,15 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Tocar para configurar ou abrir"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Toque para configurar ou abrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Definições do espaço privado"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear espaço privado"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privado, desbloqueado."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privado, bloqueado."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transição do espaço privado"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instale apps no espaço privado"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu adicional"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index c0e4457..364c247 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Anotações"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicionar o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Informações úteis ao seu alcance"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Para acessar informações sem precisar abrir os apps, adicione widgets à sua tela inicial"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para mudar as configurações do widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Ok"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Mudar as configurações do widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar apps"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Carregando apps…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Toque para configurar ou abrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Particular"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear o Espaço particular"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privada, desbloqueado."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privada, bloqueado."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Espaço particular em transição"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalar apps no espaço privado"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Balão flutuante"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 0cfaad4..a7674c7 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Luare de notițe"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Adaugă"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adaugă widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Informații utile la îndemâna ta"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Pentru a primi informații fără să deschizi aplicațiile, poți adăuga widgeturi pe ecranul de pornire"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Atinge ca să schimbi setările pentru widgeturi"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifică setările pentru widgeturi"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Caută aplicații"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Se încarcă aplicații…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Atinge pentru a configura sau a deschide"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Setări spațiu privat"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blochează / deblochează spațiul privat"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, deblocat."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, blocat."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Blochează"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Tranziție pentru spațiul privat"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalează aplicații"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalează aplicații în Spațiul privat"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Suplimentar"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index c0f3baa..c1bd999 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Вся нужная информация перед глазами"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Чтобы не открывать приложения каждый раз, когда нужна информация, добавьте виджеты на главный экран."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Нажмите, чтобы изменить настройки виджета"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"ОК"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Убрать"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Удалить"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"О приложении"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Приватная установка"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Частная установка"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
@@ -188,14 +185,16 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Возобновить"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Фильтр"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
- <string name="private_space_label" msgid="2359721649407947001">"Личное пространство"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Частное пространство"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Нажмите, чтобы настроить или открыть"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Доступно только вам"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Настройки личного пространства"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Блокировка и разблокировка личного пространства"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Личное, разблокировано."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Личное, заблокировано."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Блокировка"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Переход к личному пространству"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Установить приложения"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Установить приложения в личном пространстве"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дополнительное меню"</string>
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 89594c5..a48cb7f 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"ප්රයෝජනවත් තොරතුරු ඔබගේ ඇඟිලි තුඩු අග"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"යෙදුම් විවෘත නොකර තොරතුරු ලබා ගැනීම සඳහා, ඔබට ඔබගේ මුල් තිරයට විජට් එක් කළ හැකිය"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"විජට් සැකසීම් වෙනස් කිරීමට තට්ටු කරන්න"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"තේරුණා"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"පිහිටුවීමට හෝ විවෘත කිරීමට තට්ටු කරන්න"</string>
<string name="ps_container_title" msgid="4391796149519594205">"පෞද්ගලික"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"පෞද්ගලික අවකාශ සැකසීම්"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"පෞද්ගලික අවකාශය අගුළු දමන්න/අගුළු හරින්න"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"පුද්ගලි, අගුලු හරින ලදි."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"පුද්ගලික, අගුලු දමන ලදි."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"අගුළු දමන්න"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"පෞද්ගලික අවකාශ සංක්රමණය"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"යෙදුම් ස්ථාපනය කරන්න"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"පෞද්ගලික අවකාශයට යෙදුම් ස්ථාපනය කරන්න"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"පිටාර යාම"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index cf87cf8..1ca6fe5 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Zapisovanie poznámok"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Pridať"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridať miniaplikáciu <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Užitočné informácie poruke"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Ak chcete získavať informácie bez otvárania aplikácií, môžete si na plochu pridať miniaplikácie"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím zmeňte nastavenia miniaplikácie"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Dobre"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Zmena nastavení miniaplikácie"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hľadať aplikácie"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Načítavajú sa aplikácie…"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Klepnutím nastavte alebo otvorte"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Súkromné"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavenia súkromného priestoru"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Súkromný priestor zamykania a odomykania"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Súkromné, odomknuté."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Súkromné, uzamknuté."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Uzamknúť"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prechod súkromného priestoru"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Inštalovať aplikácie"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Inštalácia aplikácií v súkromnom priestore"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozšírená ponuka"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 7184d7e..8ce593c 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ustvarjanje zapiskov"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajanje pripomočka »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>«"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Koristne informacije na dosegu prstov"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Če si želite podatke ogledati brez odpiranja aplikacij, lahko na začetni zaslon dodate pripomočke."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dotaknite se, če želite spremeniti nastavitve pripomočka."</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Razumem"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Spreminjanje nastavitev pripomočka"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Iskanje programov"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Nalaganje aplikacij …"</string>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podatki o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Namesti v zasebno"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj aplikacij"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</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>
@@ -189,13 +186,15 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtriranje"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Zasebni prostor"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Dotaknite se, da nastavite ali odprete"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Dotaknite se, da ga nastavite ali odprete"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Zasebno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavitve zasebnega prostora"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaklepanje/odklepanje zasebnega prostora"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Zasebno, odklenjeno."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Zasebno, zaklenjeno."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zaklepanje"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Preklapljanje zasebnega prostora"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Nameščanje aplikacij"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Nameščanje aplikacij v zasebni prostor"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oblaček z dodatnimi elementi"</string>
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 29b3416..aa1ff2b 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Mbajtja e shënimeve"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Shto"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Shto miniaplikacionin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Informacione të dobishme në majë të gishtave të tu"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Për të marrë informacione pa i hapur aplikacionet, mund të shtosh miniaplikacione në ekranin bazë"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trokit për të ndryshuar cilësimet e miniaplikacionit"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"E kuptova"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ndrysho cilësimet e miniaplikacionit"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Kërko për aplikacione"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Po ngarkon aplikacionet..."</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Trokit për të konfiguruar ose për të hapur"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Cilësimet e \"Hapësirës private\""</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kyç/Shkyç \"Hapësirën private\""</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Private, e shkyçur."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Private, e kyçur."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Kyç"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Kalimi te \"Hapësira private\""</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Instalo aplikacionet"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalo aplikacionet në hapësirën private"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Tejkalimi"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 9535dc0..44b26ac 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетни екран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Додали сте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> на почетни екран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предлози"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Неопходне апликације"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основно"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новости и часописи"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона за опуштање"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Забава"</string>
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Корисне информације надохват руке"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Да бисте пронашли информације без отварања апликација, можете да додате виџете на почетни екран"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Додирните да бисте променили подешавања виџета"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Важи"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Додирните да бисте подесили или отворили"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Приватно"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Подешавања приватног простора"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Закључај/откључај приватни простор"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Приватно, откључано."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Приватно, закључано."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Закључавање"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Пренос приватног простора"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталирајте апликације"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталирај апликације у приватан простор"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Преклопно"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index a3f5625..42f0414 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Anteckna"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Lägg till"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lägg till widgeten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Användbar information nära till hands"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Om du vill ha information utan att öppna appar kan du lägga till widgetar på startskärmen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryck för att ändra inställningarna för widgeten"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Ändra inställningarna för widgeten"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sök efter appar"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Läser in appar …"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Tryck för att ställa in eller öppna"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Inställningar för privat rum"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås eller lås upp ditt privata rum"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, olåst."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, låst."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Överföring av privat rum"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Installera appar"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installera appar i privat rum"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Fler alternativ"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 8d74b83..68be297 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -44,11 +44,11 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Weka kwenye skrini ya kwanza"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Umeongeza wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g> kwenye skrini ya kwanza"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Mapendekezo"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Vya msingi"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Habari na magazeti"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Mahali Pako pa Kupumzika"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Burudani"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Mitandao jamii"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Mitandao ya kijamii"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Afya na siha"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Hali ya Hewa"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Unayopendekezewa"</string>
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Kuandika madokezo"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Weka"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Weka wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Maelezo muhimu, popote ulipo"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Ili upate maelezo bila kufungua programu, unaweza kuweka wijeti kwenye skrini yako ya kwanza"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Gusa ili ubadilishe mipangilio ya wijeti"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Nimeelewa"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Badilisha mipangilio ya wijeti"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tafuta programu"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Inapakia programu..."</string>
@@ -189,13 +186,15 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Kichujio"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Nafasi ya faragha"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Gusa ili uweke mipangilio au ufungue"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Gusa uweke mipangilio au ufungue"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Faragha"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Mipangilio ya Nafasi ya Faragha"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Funga/Fungua Nafasi ya Faragha"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Ya faragha, imefunguliwa."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Ya faragha, imefungwa."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Funga"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Mabadiliko ya Nafasi ya Faragha"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Sakinisha programu"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Sakinisha programu kwenye Sehemu ya Faragha"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menyu ya vipengee vya ziada"</string>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 68f3633..68fb40f 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"விரல்நுனியில் பயனுள்ள தகவல்களைப் பெறுங்கள்"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"முகப்புத் திரையில் விட்ஜெட்டுகளைச் சேர்த்து ஆப்ஸைத் திறக்காமலேயே தகவல்களைப் பெறலாம்"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"விட்ஜெட் அமைப்புகளை மாற்றத் தட்டவும்"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"சரி"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"அமைக்கவோ திறக்கவோ தட்டுங்கள்"</string>
<string name="ps_container_title" msgid="4391796149519594205">"தனிப்பட்டது"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"தனிப்பட்ட சேமிப்பிட அமைப்புகள்"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"தனிப்பட்ட சேமிப்பிடத்தை லாக்/அன்லாக் செய்யும்"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"தனிப்பட்டது, அன்லாக் செய்யப்பட்டுள்ளது."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"தனிப்பட்டது, லாக் செய்யப்பட்டுள்ளது."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"பூட்டு"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"தனிப்பட்ட சேமிப்பிடத்திற்கு மாற்றுகிறது"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ஆப்ஸை நிறுவுதல்"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"தனிப்பட்ட சேமிப்பிடத்தில் ஆப்ஸை நிறுவும்"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 4533fda..ce8fefb 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"మీ చేతివేళ్ల మీద ఉపయోగకరమైన సమాచారం"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"యాప్లను తెరవకుండా సమాచారాన్ని పొందడానికి, మీరు మీ మొదటి స్క్రీన్కు విడ్జెట్లను జోడించవచ్చు"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"విడ్జెట్ సెట్టింగ్లను మార్చడానికి ట్యాప్ చేయండి"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"అర్థమైంది"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"సెటప్ చేయడానికి లేదా తెరవడానికి ట్యాప్ చేయండి"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ప్రైవేట్"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ప్రైవేట్ స్పేస్ సెట్టింగ్లు"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ప్రైవేట్ స్పేస్ను లాక్/అన్లాక్ చేయండి"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ప్రైవేట్, అన్లాక్ చేయబడింది."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ప్రైవేట్, లాక్ చేయబడింది."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"లాక్ చేయండి"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ప్రైవేట్ స్పేస్ కేటాయించడం జరుగుతుంది"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"యాప్లను ఇన్స్టాల్ చేయండి"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ప్రైవేట్ స్పేస్కు యాప్లను ఇన్స్టాల్ చేయండి"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ఓవర్ఫ్లో"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index efcd36f..ea6c900 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"เข้าถึงข้อมูลที่เป็นประโยชน์ได้จากปลายนิ้ว"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"หากต้องการรับข้อมูลโดยไม่เปิดแอป ให้เพิ่มวิดเจ็ตลงในหน้าจอหลัก"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"แตะเพื่อเปลี่ยนการตั้งค่าวิดเจ็ต"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"รับทราบ"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"นำออก"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ถอนการติดตั้ง"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ข้อมูลแอป"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ติดตั้งในส่วนตัว"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ติดตั้งในแบบส่วนตัว"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"แตะเพื่อตั้งค่าหรือเปิด"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ส่วนตัว"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"การตั้งค่าพื้นที่ส่วนตัว"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ล็อก/ปลดล็อกพื้นที่ส่วนตัว"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ส่วนตัว ปลดล็อกอยู่"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ส่วนตัว ล็อกอยู่"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ล็อก"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"การเปลี่ยนไปใช้พื้นที่ส่วนตัว"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ติดตั้งแอป"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ติดตั้งแอปไปยังพื้นที่ส่วนตัว"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"การดำเนินการเพิ่มเติม"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 27c2dd8..4b5b144 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pagtatala"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Idagdag"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Idagdag ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Abot-kamay na mahalagang impormasyon"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Para makakuha ng impormasyon nang hindi nagbubukas ng mga app, puwede kang magdagdag ng mga widget sa iyong home screen"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"I-tap para baguhin ang mga setting ng widget"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Baguhin ang mga setting ng widget"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Maghanap ng mga app"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Naglo-load ng mga app…"</string>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Impormasyon ng app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pribadong i-install"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi ng app"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi"</string>
<string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"I-tap para i-set up o buksan"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Pribado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Mga Setting ng Pribadong Space"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"I-lock/I-unlock ang Pribadong Space"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Pribado, naka-unlock."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Pribado, naka-lock."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"I-lock"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Pag-transition ng Pribadong Space"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Mag-install ng mga app"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Mag-install ng mga app sa Pribadong Space"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 9e723dd..ae30c1d 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Not alma"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Ekle"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ekle"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Faydalı bilgiler parmaklarınızın ucunda"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Uygulama açmadan bilgi almak için ana ekranınıza widget ekleyebilirsiniz"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Widget ayarlarını değiştirmek için dokunun"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Anladım"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widget ayarlarını değiştir"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Uygulamalarda ara"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Uygulamalar yükleniyor…"</string>
@@ -89,9 +86,9 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"Sil"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Kaldır"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükleyin"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükle"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulama önerme"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Kurmak veya açmak için dokunun"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Gizli"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Gizli Alan Ayarları"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Gizli Alanı Kilitleyin/Kilidini Açın"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Gizli, kilidi açık."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Gizli, kilitli."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Kilit"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Gizli Alana Geçiş"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Uygulamaları yükleme"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Uygulamaları özel alana yükleyin"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Taşma"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 9552a57..5f9f17d 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"Корисна інформація завжди під рукою"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Щоб отримувати інформацію, не відкриваючи додатки, ви можете додати на головний екран віджети"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Натисніть, щоб змінити налаштування віджета"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</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>
@@ -189,13 +186,15 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не вдалося <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватний простір"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Натисніть, щоб налаштувати або відкрити"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Натисніть, щоб налаштувати чи відкрити"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Приватні"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Налаштування приватного простору"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблокувати/розблокувати приватний простір"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Приватний простір, розблоковано."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Приватний простір, заблоковано."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Заблокувати"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Перехід у приватний простір"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Установити додатки"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Установити додатки в особистому просторі"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Додаткове меню"</string>
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 50334a0..e468de9 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"مفید معلومات کو آسانی سے حاصل کریں"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"ایپس کو کھولے بغیر معلومات حاصل کرنے کے لیے آپ اپنی ہوم اسکرین پر ویجیٹس شامل کر سکتے ہیں"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ویجیٹ ترتیبات تبدیل کرنے کے لیے تھپتھپائیں"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"سمجھ آ گئی"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"سیٹ اپ کرنے یا کھولنے کے لیے تھپتھپائیں"</string>
<string name="ps_container_title" msgid="4391796149519594205">"نجی"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"نجی اسپیس کی ترتیبات"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"نجی اسپیس کو مقفل کریں/غیر مقفل کریں"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"نجی اسپیس غیر مقفل ہے۔"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"نجی اسپیس مقفل ہے۔"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"مقفل کریں"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"نجی اسپیس کی منتقلی"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"ایپس انسٹال کریں"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"پرائیویٹ اسپیس میں ایپس انسٹال کریں"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"اوورفلو"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 89ccde3..28d2dcf 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Qayd olish"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Chiqarish"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjetini chiqarish"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Barcha kerakli axborot doim yoningizda"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Kerakli ilovalarni ochmasdan turib ulardan axborot olish uchun vidjetlarni bosh ekranga chiqaring"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidjet sozlamalarini oʻzgartirish uchun bosing"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Vidjet sozlamalarini oʻzgartirish"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Ilovalarni qidirish"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Ilovalar yuklanmoqda…"</string>
@@ -190,12 +187,14 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Shaxsiy xona"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Sozlash yoki ochish uchun bosing"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Yopiq"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Maxfiy"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Shaxsiy xona sozlamalari"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Shaxsiy xonani ochish/qulflash"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Shaxsiy, ochildi."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Shaxsiy, qulflandi."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Qulflash"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Maxfiy joyga almashtirish"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Ilovalar oʻrnatish"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Ilovalarni Maxfiy makonga oʻrnatish"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kengaytirish"</string>
</resources>
diff --git a/res/values-v34/colors.xml b/res/values-v34/colors.xml
new file mode 100644
index 0000000..26d3712
--- /dev/null
+++ b/res/values-v34/colors.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <color name="widget_picker_secondary_surface_color_light">
+ @android:color/system_surface_bright_light</color>
+ <color name="widget_picker_header_app_title_color_light">
+ @android:color/system_on_surface_light</color>
+ <color name="widget_picker_header_app_subtitle_color_light">
+ @android:color/system_on_surface_variant_light</color>
+ <color name="widget_cell_title_color_light">
+ @android:color/system_on_surface_light</color>
+ <color name="widget_cell_subtitle_color_light">
+ @android:color/system_on_surface_variant_light</color>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 448d2a2..25f1453 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ghi chú"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Thêm"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Thông tin hữu ích ngay trong tầm tay bạn"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Để nhận thông tin mà không cần mở các ứng dụng, bạn có thể thêm tiện ích vào màn hình chính"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Nhấn để thay đổi chế độ cài đặt tiện ích"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Tôi hiểu"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Thay đổi chế độ cài đặt tiện ích"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tìm kiếm ứng dụng"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Đang tải ứng dụng…"</string>
@@ -91,7 +88,7 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"Thông tin ứng dụng"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Cài đặt ở chế độ riêng tư"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"Không đề xuất ứng dụng"</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="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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Nhấn để thiết lập hoặc mở"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Riêng tư"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Cài đặt không gian riêng tư"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khoá/mở khoá không gian riêng tư"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Riêng tư, đã mở khoá."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Riêng tư, đã khoá."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Khoá"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Chuyển đổi sang không gian riêng tư"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Cài đặt ứng dụng"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Cài đặt ứng dụng vào Không gian riêng tư"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Bong bóng bổ sung"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index d675db3..ab44d5d 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"添加到主屏幕"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已将“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件添加到主屏幕"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建议"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必备"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必备之选"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"新闻与杂志"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"您的休闲区"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"娱乐"</string>
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"实用信息触手可及"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"要想不打开应用就能获取信息,您可以将相应微件添加到主屏幕"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"点按即可更改微件设置"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"知道了"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"点按即可设置或打开"</string>
<string name="ps_container_title" msgid="4391796149519594205">"私密"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"私密空间设置"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"锁定/解锁私密空间"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"私密,未锁定。"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"私密,已锁定。"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"锁定"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"私密空间转换"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"安装应用"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"将应用安装到私密空间"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"菜单"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e9c968a..a83856f 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"實用資訊,唾手可得"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"只要將小工具新增至主畫面,就可以直接查看資料,無需開啟應用程式"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕按即可變更小工具設定"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"知道了"</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>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"輕按即可設定或開啟"</string>
<string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"「私人空間」設定"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/解鎖「私人空間」"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"私人,未鎖定。"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"私人,已鎖定。"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"上鎖"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"轉為「私人空間」"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"安裝應用程式"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"將應用程式安裝在「私人空間」中"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"顯示更多"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index e891ee2..76a76a2 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -67,10 +67,7 @@
<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="widget_education_header" msgid="4874760613775913787">"實用資訊隨手可得"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"只要將小工具新增到主畫面,就可以直接查看資訊,不必開啟應用程式"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕觸即可變更小工具設定"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"我知道了"</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>
@@ -89,7 +86,7 @@
<string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資訊"</string>
- <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人資料夾中"</string>
+ <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人空間中"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"輕觸即可設定或開啟"</string>
<string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"私人空間設定"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/取消鎖定私人空間"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"私人,未鎖定。"</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"私人,已鎖定。"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"鎖定"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"轉換私人空間狀態"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"安裝應用程式"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"將應用程式安裝在私人空間中"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"溢位"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 7a0871a..8af4a93 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -67,10 +67,7 @@
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ukuthatha amanothi"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Engeza"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Engeza iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Ulwazi oluwusizo phambi nje kwakho"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Ukuze uthole ulwazi ngaphandle kokuvula ama-app, ungakwazi ukwengeza amawijethi kusikrini sakho sasekhaya"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Thepha ukuze ushintshe amasethingi ewijethi"</string>
- <string name="widget_education_close_button" msgid="8676165703104836580">"Ngiyezwa"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Shintsha amasethingi ewijethi"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sesha izinhlelo zokusebenza"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Ilayisha izinhlelo zokusebenza..."</string>
@@ -192,10 +189,12 @@
<string name="private_space_secondary_label" msgid="9203933341714508907">"Thepha ukuze usethe noma uvule"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Okuyimfihlo"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Amasethingi Esikhala Esiyimfihlo"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khiya/Vula Isikhala Esiyimfihlo"</string>
+ <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Iyimfihlo, ivuliwe."</string>
+ <string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Iyimfihlo, ikhiyiwe."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Khiya"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Ukuguqulwa Kwendawo Yangasese"</string>
- <string name="ps_add_button_label" msgid="8611055839242385935">"Faka ama-app"</string>
+ <!-- no translation found for ps_add_button_label (8127988716897128773) -->
+ <skip />
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Faka ama-app Endaweni Engasese"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ukugcwala kakhulu"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index f23c790..be8b2e1 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -76,6 +76,8 @@
<attr name="widgetPickerCollapseHandleColor" format="color"/>
<attr name="widgetPickerAddButtonBackgroundColor" format="color"/>
<attr name="widgetPickerAddButtonTextColor" format="color"/>
+ <attr name="widgetCellTitleColor" format="color" />
+ <attr name="widgetCellSubtitleColor" format="color" />
<!-- BubbleTextView specific attributes. -->
<declare-styleable name="BubbleTextView">
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a620eb0..ce80964 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -90,6 +90,8 @@
<color name="drop_target_hover_button_color_light">#D3E3FD</color>
<color name="drop_target_hover_button_color_dark">#0842A0</color>
+ <color name="taskbar_running_app_indicator_color">#000000</color>
+
<color name="preload_icon_accent_color_light">#00668B</color>
<color name="preload_icon_background_color_light">#B5CAD7</color>
<color name="preload_icon_accent_color_dark">#4BB6E8</color>
@@ -115,6 +117,8 @@
<color name="widget_picker_collapse_handle_color_light">#C4C7C5</color>
<color name="widget_picker_add_button_background_color_light">#0B57D0</color>
<color name="widget_picker_add_button_text_color_light">#0B57D0</color>
+ <color name="widget_cell_title_color_light">@color/material_color_on_surface</color>
+ <color name="widget_cell_subtitle_color_light">@color/material_color_on_surface_variant</color>
<color name="widget_picker_primary_surface_color_dark">#1F2020</color>
<color name="widget_picker_secondary_surface_color_dark">#393939</color>
@@ -132,6 +136,8 @@
<color name="widget_picker_collapse_handle_color_dark">#444746</color>
<color name="widget_picker_add_button_background_color_dark">#062E6F</color>
<color name="widget_picker_add_button_text_color_dark">#FFFFFF</color>
+ <color name="widget_cell_title_color_dark">@color/material_color_on_surface</color>
+ <color name="widget_cell_subtitle_color_dark">@color/material_color_on_surface_variant</color>
<color name="material_color_on_secondary_fixed_variant">#3F4759</color>
<color name="material_color_on_tertiary_fixed_variant">#583E5B</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 7938b9a..6767a47 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -76,6 +76,7 @@
<string name="taskbar_model_callbacks_factory_class" translatable="false"></string>
<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>
<!-- 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>
@@ -222,4 +223,11 @@
<string-array name="skip_private_profile_shortcut_packages" translatable="false">
<item>com.android.settings</item>
</string-array>
+
+ <!-- Legacy list of components supporting multiple instances.
+ DO NOT ADD TO THIS LIST. Apps should use the PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI
+ property to declare multi-instance support in V+. This resource should match the resource
+ of the same name in SystemUI. -->
+ <string-array name="config_appsSupportMultiInstancesSplit">
+ </string-array>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5ff9902..54edab4 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -179,19 +179,39 @@
<!-- Widget tray -->
<dimen name="widget_cell_vertical_padding">8dp</dimen>
<dimen name="widget_cell_horizontal_padding">8dp</dimen>
- <dimen name="widget_cell_font_size">14sp</dimen>
+ <dimen name="widget_cell_title_font_size">14sp</dimen>
+ <integer name="widget_cell_title_font_weight">500</integer>
+ <dimen name="widget_cell_title_line_height">20sp</dimen>
+ <dimen name="widget_cell_dims_font_size">14sp</dimen>
+ <integer name="widget_cell_dims_font_weight">400</integer>
+ <dimen name="widget_cell_dims_line_height">20sp</dimen>
+ <dimen name="widget_cell_description_font_size">12sp</dimen>
+ <integer name="widget_cell_description_font_weight">400</integer>
+ <dimen name="widget_cell_description_line_height">16sp</dimen>
<dimen name="widget_cell_app_icon_size">24dp</dimen>
<dimen name="widget_cell_app_icon_padding">8dp</dimen>
<dimen name="widget_cell_add_button_height">48dp</dimen>
<dimen name="widget_cell_add_button_start_padding">8dp</dimen>
+ <dimen name="widget_cell_add_icon_button_start_padding">16dp</dimen>
<dimen name="widget_cell_add_button_end_padding">16dp</dimen>
<dimen name="widget_cell_add_button_scroll_padding">24dp</dimen>
+ <dimen name="widget_cell_add_button_font_size">14sp</dimen>
+ <integer name="widget_cell_add_button_font_weight">500</integer>
+ <dimen name="widget_cell_add_button_line_height">20sp</dimen>
+ <dimen name="widget_cell_add_button_drawable_padding">8dp</dimen>
+ <dimen name="widget_cell_add_button_drawable_width">19dp</dimen>
<dimen name="widget_tabs_button_horizontal_padding">4dp</dimen>
<dimen name="widget_tabs_horizontal_padding">16dp</dimen>
<dimen name="widget_apps_tabs_vertical_padding">6dp</dimen>
<dimen name="widget_picker_landscape_tablet_left_right_margin">117dp</dimen>
<dimen name="widget_picker_two_panels_left_right_margin">0dp</dimen>
+ <dimen name="widget_picker_header_app_title_font_size">16sp</dimen>
+ <integer name="widget_picker_header_app_title_font_weight">500</integer>
+ <dimen name="widget_picker_header_app_title_line_height">24sp</dimen>
+ <dimen name="widget_picker_header_app_subtitle_font_size">14sp</dimen>
+ <integer name="widget_picker_header_app_subtitle_font_weight">400</integer>
+ <dimen name="widget_picker_header_app_subtitle_line_height">20sp</dimen>
<dimen name="widget_recommendations_table_vertical_padding">8dp</dimen>
<!-- Bottom margin for the search and recommended widgets container without work profile -->
<dimen name="search_and_recommended_widgets_container_bottom_margin">16dp</dimen>
@@ -209,6 +229,8 @@
<dimen name="widget_list_left_pane_horizontal_margin">0dp</dimen>
<dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
<dimen name="widget_picker_vertical_margin_right_pane">24dp</dimen>
+ <!-- Margin on sides of the widgets scrollview in widgets bottom sheet -->
+ <dimen name="widget_bottom_sheet_horizontal_margin">16dp</dimen>
<dimen name="widget_preview_shadow_blur">0.5dp</dimen>
<dimen name="widget_preview_key_shadow_distance">1dp</dimen>
@@ -392,6 +414,9 @@
<dimen name="min_hotseat_icon_space">18dp</dimen>
<dimen name="max_hotseat_icon_space">50dp</dimen>
<dimen name="min_hotseat_qsb_width">0dp</dimen>
+ <dimen name="taskbar_running_app_indicator_height">0dp</dimen>
+ <dimen name="taskbar_running_app_indicator_width">0dp</dimen>
+ <dimen name="taskbar_running_app_indicator_top_margin">0dp</dimen>
<!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="transient_taskbar_padding">0dp</dimen>
@@ -476,6 +501,7 @@
<dimen name="bottom_sheet_handle_width">32dp</dimen>
<dimen name="bottom_sheet_handle_height">4dp</dimen>
<dimen name="bottom_sheet_handle_margin">16dp</dimen>
+ <dimen name="widgets_bottom_sheet_handle_margin">24dp</dimen>
<dimen name="bottom_sheet_handle_corner_radius">2dp</dimen>
<!-- State transition -->
@@ -490,13 +516,13 @@
<dimen name="default_ime_height">300dp</dimen>
<!-- Private Space parameters -->
- <dimen name="ps_container_corner_radius">24dp</dimen>
- <dimen name="ps_header_height">64dp</dimen>
+ <dimen name="ps_container_corner_radius">28dp</dimen>
+ <dimen name="ps_header_height">72dp</dimen>
<dimen name="ps_header_relative_layout_height">48dp</dimen>
<dimen name="ps_header_image_height">48dp</dimen>
<dimen name="ps_header_text_height">24dp</dimen>
<dimen name="ps_header_layout_margin">16dp</dimen>
- <dimen name="ps_header_settings_icon_margin_end">4dp</dimen>
+ <dimen name="ps_lock_button_margin_end">12dp</dimen>
<dimen name="ps_header_text_size">16sp</dimen>
<dimen name="ps_button_height">40dp</dimen>
<dimen name="ps_button_width">40dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e1c7d64..c3d4273 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -139,20 +139,10 @@
placeholder text is the widget name. [CHAR_LIMIT=none] -->
<string name="widget_add_button_content_description">Add <xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget</string>
- <!-- Title of a dialog. This dialog lets a user know how they can use widgets on their phone.
- [CHAR_LIMIT=NONE] -->
- <string name="widget_education_header">Useful info at your fingertips</string>
- <!-- Dialog text. This dialog lets a user know how they can use widgets on their phone.
- [CHAR_LIMIT=NONE] -->
- <string name="widget_education_content">To get info without opening apps, you can add widgets to your home screen</string>
-
<!-- Text on an educational tip on widget informing users that they can change widget settings.
[CHAR_LIMIT=NONE] -->
<string name="reconfigurable_widget_education_tip">Tap to change widget settings</string>
- <!-- Text on the button that closes the education dialog about widgets. [CHAR_LIMIT=50] -->
- <string name="widget_education_close_button">Got it</string>
-
<!-- Spoken text for screen readers. This text is for an icon that lets the user change a
widget's settings. [CHAR_LIMIT=50] -->
<string name="widget_reconfigure_button_content_description">Change widget settings</string>
@@ -487,13 +477,15 @@
<string name="ps_container_title">Private</string>
<!-- Description for Private Space Settings button -->
<string name="ps_container_settings">Private Space Settings</string>
- <!-- Description for Private Space Lock/Unlock button -->
- <string name="ps_container_lock_unlock_button">Lock/Unlock Private Space</string>
+ <!-- Description for Private Space Unlock button -->
+ <string name="ps_container_unlock_button_content_description">Private, unlocked.</string>
+ <!-- Description for Private Space Lock button -->
+ <string name="ps_container_lock_button_content_description">Private, locked.</string>
<string name="ps_container_lock_title">Lock</string>
<!-- Description for Private Space Transition button -->
<string name="ps_container_transition">Private Space Transitioning</string>
<!-- Title for Private Space install app icon -->
- <string name="ps_add_button_label">Install apps</string>
+ <string name="ps_add_button_label">Install</string>
<!-- Content description for install app icon -->
<string name="ps_add_button_content_description">Install apps to Private Space</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 00b962e..6d99084 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -268,6 +268,10 @@
@color/widget_picker_add_button_background_color_light</item>
<item name="widgetPickerAddButtonTextColor">
@color/widget_picker_add_button_text_color_light</item>
+ <item name="widgetCellTitleColor">
+ @color/widget_cell_title_color_light</item>
+ <item name="widgetCellSubtitleColor">
+ @color/widget_cell_subtitle_color_light</item>
</style>
<style name="WidgetContainerTheme.Dark" parent="AppTheme.Dark">
<item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
@@ -303,6 +307,10 @@
@color/widget_picker_add_button_background_color_dark</item>
<item name="widgetPickerAddButtonTextColor">
@color/widget_picker_add_button_text_color_dark</item>
+ <item name="widgetCellTitleColor">
+ @color/widget_cell_title_color_dark</item>
+ <item name="widgetCellSubtitleColor">
+ @color/widget_cell_subtitle_color_dark</item>
</style>
<style name="FastScrollerPopup" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 4ccf3db..876b643 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -70,7 +70,6 @@
TYPE_ICON_SURFACE,
TYPE_OPTIONS_POPUP_DIALOG,
TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP,
- TYPE_WIDGETS_EDUCATION_DIALOG,
TYPE_TASKBAR_EDUCATION_DIALOG,
TYPE_TASKBAR_ALL_APPS,
TYPE_ADD_TO_HOME_CONFIRMATION,
@@ -98,7 +97,6 @@
public static final int TYPE_OPTIONS_POPUP_DIALOG = 1 << 14;
public static final int TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP = 1 << 15;
- public static final int TYPE_WIDGETS_EDUCATION_DIALOG = 1 << 16;
public static final int TYPE_TASKBAR_EDUCATION_DIALOG = 1 << 17;
public static final int TYPE_TASKBAR_ALL_APPS = 1 << 18;
public static final int TYPE_ADD_TO_HOME_CONFIRMATION = 1 << 19;
@@ -111,16 +109,16 @@
| TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
| TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
| TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
- | TYPE_WIDGETS_EDUCATION_DIALOG | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS
- | TYPE_OPTIONS_POPUP_DIALOG | TYPE_ADD_TO_HOME_CONFIRMATION
- | TYPE_TASKBAR_OVERLAY_PROXY | TYPE_TASKBAR_PINNING_POPUP | TYPE_PIN_IME_POPUP;
+ | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG
+ | TYPE_ADD_TO_HOME_CONFIRMATION | TYPE_TASKBAR_OVERLAY_PROXY
+ | TYPE_TASKBAR_PINNING_POPUP | TYPE_PIN_IME_POPUP;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
- | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG
- | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG
- | TYPE_TASKBAR_OVERLAY_PROXY | TYPE_PIN_IME_POPUP;
+ | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_TASKBAR_EDUCATION_DIALOG
+ | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG | TYPE_TASKBAR_OVERLAY_PROXY
+ | TYPE_PIN_IME_POPUP;
/** Type of popups that should get exclusive accessibility focus. */
public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index b46d7e2..b51e850 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -136,6 +136,7 @@
private final Rect mWidgetViewNewRect = new Rect();
private final @Nullable LauncherAppWidgetHostView.CellChildViewPreLayoutListener
mCellChildViewPreLayoutListener;
+ private final @NonNull OnLayoutChangeListener mWidgetViewLayoutListener;
private int mXDown, mYDown;
@@ -177,6 +178,9 @@
mDragAcrossTwoPanelOpacityMargin = mLauncher.getResources().getDimensionPixelSize(
R.dimen.resize_frame_invalid_drag_across_two_panel_opacity_margin);
mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
+
+ mWidgetViewLayoutListener =
+ (v, l, t, r, b, oldL, oldT, oldR, oldB) -> setCornerRadiusFromWidget();
}
@Override
@@ -211,15 +215,6 @@
DragLayer dl = launcher.getDragLayer();
AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
.inflate(R.layout.app_widget_resize_frame, dl, false);
- if (widget.hasEnforcedCornerRadius()) {
- float enforcedCornerRadius = widget.getEnforcedCornerRadius();
- ImageView imageView = frame.findViewById(R.id.widget_resize_frame);
- Drawable d = imageView.getDrawable();
- if (d instanceof GradientDrawable) {
- GradientDrawable gd = (GradientDrawable) d.mutate();
- gd.setCornerRadius(enforcedCornerRadius);
- }
- }
frame.setupForWidget(widget, cellLayout, dl);
((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
@@ -228,6 +223,18 @@
frame.post(() -> frame.snapToWidget(false));
}
+ private void setCornerRadiusFromWidget() {
+ if (mWidgetView != null && mWidgetView.hasEnforcedCornerRadius()) {
+ float enforcedCornerRadius = mWidgetView.getEnforcedCornerRadius();
+ ImageView imageView = findViewById(R.id.widget_resize_frame);
+ Drawable d = imageView.getDrawable();
+ if (d instanceof GradientDrawable) {
+ GradientDrawable gd = (GradientDrawable) d.mutate();
+ gd.setCornerRadius(enforcedCornerRadius);
+ }
+ }
+ }
+
private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
DragLayer dragLayer) {
mCellLayout = cellLayout;
@@ -317,6 +324,9 @@
.log(LAUNCHER_WIDGET_RESIZE_STARTED);
setOnKeyListener(this);
+
+ setCornerRadiusFromWidget();
+ mWidgetView.addOnLayoutChangeListener(mWidgetViewLayoutListener);
}
public boolean beginResizeIfPointInRegion(int x, int y) {
@@ -729,6 +739,7 @@
mWidgetView.setLayoutTransition(null);
}
mDragLayer.removeView(this);
+ mWidgetView.removeOnLayoutChangeListener(mWidgetViewLayoutListener);
}
private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 1049314..633091d 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -412,6 +412,8 @@
public static <T extends BaseActivity> T fromContext(Context context) {
if (context instanceof BaseActivity) {
return (T) context;
+ } else if (context instanceof ActivityContextDelegate) {
+ return (T) ((ActivityContextDelegate) context).mDelegate;
} else if (context instanceof ContextWrapper) {
return fromContext(((ContextWrapper) context).getBaseContext());
} else {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 83236d1..2a8298f 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -46,6 +46,7 @@
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Property;
+import android.util.Size;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -182,6 +183,13 @@
private Animator mDotScaleAnim;
private boolean mForceHideDot;
+ // These fields, related to showing running apps, are only used for Taskbar.
+ private final Size mRunningAppIndicatorSize;
+ private final int mRunningAppIndicatorTopMargin;
+ private final Paint mRunningAppIndicatorPaint;
+ private final Rect mRunningAppIconBounds = new Rect();
+ private boolean mIsRunning;
+
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mStayPressed;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -248,6 +256,16 @@
defaultIconSize);
a.recycle();
+ mRunningAppIndicatorSize = new Size(
+ getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_width),
+ getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_height));
+ mRunningAppIndicatorTopMargin =
+ getResources().getDimensionPixelSize(
+ R.dimen.taskbar_running_app_indicator_top_margin);
+ mRunningAppIndicatorPaint = new Paint();
+ mRunningAppIndicatorPaint.setColor(getResources().getColor(
+ R.color.taskbar_running_app_indicator_color, context.getTheme()));
+
mLongPressHelper = new CheckLongPressHelper(this);
mDotParams = new DotRenderer.DrawParams();
@@ -394,6 +412,12 @@
setDownloadStateContentDescription(info, info.getProgressLevel());
}
+ /** Updates whether the app this view represents is currently running. */
+ @UiThread
+ public void updateRunningState(boolean isRunning) {
+ mIsRunning = isRunning;
+ }
+
protected void setItemInfo(ItemInfoWithIcon itemInfo) {
setTag(itemInfo);
}
@@ -620,6 +644,7 @@
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawDotIfNecessary(canvas);
+ drawRunningAppIndicatorIfNecessary(canvas);
}
/**
@@ -631,7 +656,7 @@
if (!mForceHideDot && (hasDot() || mDotParams.scale > 0)) {
getIconBounds(mDotParams.iconBounds);
Utilities.scaleRectAboutCenter(mDotParams.iconBounds,
- IconShape.getNormalizationScale());
+ IconShape.INSTANCE.get(getContext()).getNormalizationScale());
final int scrollX = getScrollX();
final int scrollY = getScrollY();
canvas.translate(scrollX, scrollY);
@@ -640,6 +665,22 @@
}
}
+ /** Draws a line under the app icon if this is representing a running app in Desktop Mode. */
+ protected void drawRunningAppIndicatorIfNecessary(Canvas canvas) {
+ if (!mIsRunning || mDisplay != DISPLAY_TASKBAR) {
+ return;
+ }
+ getIconBounds(mRunningAppIconBounds);
+ // TODO(b/333872717): update color, shape, and size of indicator
+ int indicatorTop = mRunningAppIconBounds.bottom + mRunningAppIndicatorTopMargin;
+ canvas.drawRect(
+ mRunningAppIconBounds.centerX() - mRunningAppIndicatorSize.getWidth() / 2,
+ indicatorTop,
+ mRunningAppIconBounds.centerX() + mRunningAppIndicatorSize.getWidth() / 2,
+ indicatorTop + mRunningAppIndicatorSize.getHeight(),
+ mRunningAppIndicatorPaint);
+ }
+
@Override
public void setForceHideDot(boolean forceHideDot) {
if (mForceHideDot == forceHideDot) {
@@ -1230,4 +1271,13 @@
public boolean canShowLongPressPopup() {
return getTag() instanceof ItemInfo && ShortcutUtil.supportsShortcuts((ItemInfo) getTag());
}
+
+ /** Returns the package name of the app this icon represents. */
+ public String getTargetPackageName() {
+ Object tag = getTag();
+ if (tag instanceof ItemInfo itemInfo) {
+ return itemInfo.getTargetPackage();
+ }
+ return null;
+ }
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 72758f2..7e9e864 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -33,7 +33,6 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -115,7 +114,6 @@
@Thunk final int[] mTempLocation = new int[2];
@Thunk final Rect mTempOnDrawCellToRect = new Rect();
- final PointF mTmpPointF = new PointF();
protected GridOccupancy mOccupied;
public GridOccupancy mTmpOccupied;
@@ -123,7 +121,7 @@
private OnTouchListener mInterceptTouchListener;
private final ArrayList<DelegatedCellDrawing> mDelegatedCellDrawings = new ArrayList<>();
- final PreviewBackground mFolderLeaveBehind = new PreviewBackground();
+ final PreviewBackground mFolderLeaveBehind = new PreviewBackground(getContext());
private static final int[] BACKGROUND_STATE_ACTIVE = new int[] { android.R.attr.state_active };
private static final int[] BACKGROUND_STATE_DEFAULT = EMPTY_STATE_SET;
@@ -197,16 +195,11 @@
public static final int REORDER_ANIMATION_DURATION = 150;
@Thunk final float mReorderPreviewAnimationMagnitude;
- private final ArrayList<View> mIntersectingViews = new ArrayList<>();
- private final Rect mOccupiedRect = new Rect();
public final int[] mDirectionVector = new int[2];
ItemConfiguration mPreviousSolution = null;
- private static final int INVALID_DIRECTION = -100;
private final Rect mTempRect = new Rect();
- private final RectF mTempRectF = new RectF();
- private final float[] mTmpFloatArray = new float[4];
private static final Paint sPaint = new Paint();
@@ -1163,9 +1156,6 @@
mDragCellSpan[0] = spanX;
mDragCellSpan[1] = spanY;
- // Apply color extraction on a widget when dragging.
- applyColorExtractionOnWidget(dragObject, mDragCell, spanX, spanY);
-
final int oldIndex = mDragOutlineCurrent;
mDragOutlineAnims[oldIndex].animateOut();
mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
@@ -1186,19 +1176,6 @@
}
}
- /** Applies the local color extraction to a dragging widget object. */
- private void applyColorExtractionOnWidget(DropTarget.DragObject dragObject, int[] targetCell,
- int spanX, int spanY) {
- // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable.
- View view = dragObject.dragView.getContentView();
- if (view instanceof LauncherAppWidgetHostView) {
- int screenId = mCellLayoutContainer.getCellLayoutId(this);
- cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect);
-
- ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, this, screenId);
- }
- }
-
@SuppressLint("StringFormatMatches")
public String getItemMoveDescription(int cellX, int cellY) {
if (mContainerType == HOTSEAT) {
diff --git a/src/com/android/launcher3/DevicePaddings.java b/src/com/android/launcher3/DevicePaddings.java
index 08fb47b..8494d11 100644
--- a/src/com/android/launcher3/DevicePaddings.java
+++ b/src/com/android/launcher3/DevicePaddings.java
@@ -47,7 +47,7 @@
private static final String WORKSPACE_BOTTOM_PADDING = "workspaceBottomPadding";
private static final String HOTSEAT_BOTTOM_PADDING = "hotseatBottomPadding";
- private static final String TAG = DevicePaddings.class.getSimpleName();
+ private static final String TAG = "DevicePaddings";
private static final boolean DEBUG = false;
ArrayList<DevicePadding> mDevicePaddings = new ArrayList<>();
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 98cb84e..54aea38 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
@@ -59,6 +60,7 @@
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Partner;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -75,7 +77,7 @@
import java.util.Objects;
import java.util.stream.Collectors;
-public class InvariantDeviceProfile {
+public class InvariantDeviceProfile implements SafeCloseable {
public static final String TAG = "IDP";
// We do not need any synchronization for this variable as its only written on UI thread.
@@ -229,14 +231,14 @@
if (!newGridName.equals(gridName)) {
LauncherPrefs.get(context).put(GRID_NAME, newGridName);
}
- LockedUserState.get(context).runOnUserUnlocked(() -> {
- new DeviceGridState(this).writeToPrefs(context);
- });
+ LockedUserState.get(context).runOnUserUnlocked(() ->
+ new DeviceGridState(this).writeToPrefs(context));
DisplayController.INSTANCE.get(context).setPriorityListener(
(displayContext, info, flags) -> {
if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS
- | CHANGE_NAVIGATION_MODE | CHANGE_TASKBAR_PINNING)) != 0) {
+ | CHANGE_NAVIGATION_MODE | CHANGE_TASKBAR_PINNING
+ | CHANGE_DESKTOP_MODE)) != 0) {
onConfigChanged(displayContext);
}
});
@@ -295,6 +297,11 @@
initGrid(context, myInfo, result, deviceType);
}
+ @Override
+ public void close() {
+ DisplayController.INSTANCE.executeIfCreated(dc -> dc.setPriorityListener(null));
+ }
+
/**
* Reinitialize the current grid after a restore, where some grids might now be disabled.
*/
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index dc7c349..b89d05e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -28,6 +28,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.Flags.enableAddAppWidgetViaConfigActivityV2;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.Flags.enableWorkspaceInflation;
import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY;
import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION;
@@ -66,7 +67,6 @@
import static com.android.launcher3.LauncherState.NO_SCALE;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
@@ -96,7 +96,9 @@
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import static com.android.launcher3.testing.shared.TestProtocol.CLOCK_ICON_DRAWABLE_LEAKING;
import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING;
@@ -421,6 +423,7 @@
@Override
@TargetApi(Build.VERSION_CODES.S)
protected void onCreate(Bundle savedInstanceState) {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onCreate: instance=" + this);
mStartupLatencyLogger = createStartupLatencyLogger(
sIsNewProcess
? LockedUserState.get(this).isUserUnlockedAtLauncherStartup()
@@ -1079,6 +1082,7 @@
@Override
protected void onStart() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onStart: instance=" + this);
TraceHelper.INSTANCE.beginSection(ON_START_EVT);
super.onStart();
if (!mDeferOverlayCallbacks) {
@@ -1092,6 +1096,7 @@
@Override
@CallSuper
protected void onDeferredResumed() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDeferredResumed: instance=" + this);
logStopAndResume(true /* isResume */);
// Process any items that were added while Launcher was away.
@@ -1261,6 +1266,13 @@
getAllAppsExitEvent().ifPresent(getStatsLogManager().logger()::log);
mAllAppsSessionLogId = null;
}
+
+ // Set screen title for Talkback
+ if (state == ALL_APPS) {
+ setTitle(R.string.all_apps_label);
+ } else {
+ setTitle(R.string.home_screen);
+ }
}
/**
@@ -1272,6 +1284,7 @@
@Override
protected void onResume() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onResume: instance=" + this);
TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT);
super.onResume();
@@ -1287,6 +1300,7 @@
@Override
protected void onPause() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onPause: instance=" + this);
// Ensure that items added to Launcher are queued until Launcher returns
ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
@@ -1361,7 +1375,7 @@
// Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
// default state, otherwise we will update to the wrong offsets in RTL
mWorkspace.lockWallpaperToDefaultPage();
- if (!ENABLE_SMARTSPACE_REMOVAL.get()) {
+ if (!enableSmartspaceRemovalToggle()) {
mWorkspace.bindAndInitFirstWorkspaceScreen();
}
mDragController.addDragListener(mWorkspace);
@@ -1701,7 +1715,7 @@
AbstractFloatingView.closeAllOpenViews(this);
getStateManager().goToState(ALL_APPS, alreadyOnHome);
if (mAppsView.isSearching()) {
- mAppsView.reset(alreadyOnHome);
+ mAppsView.getSearchUiManager().resetSearch();
}
if (mAppsView.getCurrentPage() != tab) {
mAppsView.switchToTab(tab);
@@ -1769,6 +1783,7 @@
@Override
public void onDestroy() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDestroy: instance=" + this);
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 50a597d..a4ae1c8 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -19,9 +19,9 @@
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.content.Context.RECEIVER_EXPORTED;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.LauncherPrefs.ICON_STATE;
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
@@ -52,6 +52,7 @@
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SafeCloseable;
@@ -78,14 +79,10 @@
private final RunnableList mOnTerminateCallback = new RunnableList();
- public static LauncherAppState getInstance(final Context context) {
+ public static LauncherAppState getInstance(Context context) {
return INSTANCE.get(context);
}
- public static LauncherAppState getInstanceNoCreate() {
- return INSTANCE.getNoCreate();
- }
-
public Context getContext() {
return mContext;
}
@@ -130,7 +127,7 @@
.addUserEventListener(mModel::onUserEvent);
mOnTerminateCallback.add(userChangeListener::close);
- if (ENABLE_SMARTSPACE_REMOVAL.get()) {
+ if (enableSmartspaceRemovalToggle()) {
OnSharedPreferenceChangeListener firstPagePinnedItemListener =
new OnSharedPreferenceChangeListener() {
@Override
@@ -185,7 +182,7 @@
mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
iconCacheFileName, mIconProvider);
mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
- iconCacheFileName != null);
+ PackageManagerHelper.INSTANCE.get(context), iconCacheFileName != null);
mOnTerminateCallback.add(mIconCache::close);
mOnTerminateCallback.add(mModel::destroy);
}
@@ -210,7 +207,7 @@
}
private void refreshAndReloadLauncher() {
- LauncherIcons.clearPool();
+ LauncherIcons.clearPool(mContext);
mIconCache.updateIconParams(
mInvariantDeviceProfile.fillResIconDpi, mInvariantDeviceProfile.iconBitmapSize);
mModel.forceReload();
@@ -261,7 +258,7 @@
@Override
public void onSystemIconStateChanged(String iconState) {
- IconShape.init(mContext);
+ IconShape.INSTANCE.get(mContext).pickBestShape(mContext);
refreshAndReloadLauncher();
LauncherPrefs.get(mContext).put(ICON_STATE, iconState);
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 7fdfd72..e3da389 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -48,7 +48,6 @@
import com.android.launcher3.model.AddWorkspaceItemsTask;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseLauncherBinder;
-import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.CacheDataUpdatedTask;
@@ -57,6 +56,7 @@
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.model.ModelDelegate;
import com.android.launcher3.model.ModelLauncherCallbacks;
+import com.android.launcher3.model.ModelTaskController;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.PackageInstallStateChangedTask;
import com.android.launcher3.model.PackageUpdatedTask;
@@ -82,7 +82,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CancellationException;
-import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -99,6 +98,8 @@
@NonNull
private final LauncherAppState mApp;
@NonNull
+ private final PackageManagerHelper mPmHelper;
+ @NonNull
private final ModelDbController mModelDbController;
@NonNull
private final Object mLock = new Object();
@@ -153,12 +154,13 @@
LauncherModel(@NonNull final Context context, @NonNull final LauncherAppState app,
@NonNull final IconCache iconCache, @NonNull final AppFilter appFilter,
- final boolean isPrimaryInstance) {
+ @NonNull final PackageManagerHelper pmHelper, final boolean isPrimaryInstance) {
mApp = app;
+ mPmHelper = pmHelper;
mModelDbController = new ModelDbController(context);
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
- mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel,
- isPrimaryInstance);
+ mModelDelegate = ModelDelegate.newInstance(context, app, mPmHelper, mBgAllAppsList,
+ mBgDataModel, isPrimaryInstance);
}
@NonNull
@@ -426,13 +428,9 @@
@Override
public void onInstallSessionCreated(@NonNull final PackageInstallInfo sessionInfo) {
if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
- enqueueModelUpdateTask(new BaseModelUpdateTask() {
- @Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
- apps.addPromiseApp(app.getContext(), sessionInfo);
- bindApplicationsIfNeeded();
- }
+ enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+ apps.addPromiseApp(mApp.getContext(), sessionInfo);
+ taskController.bindApplicationsIfNeeded();
});
}
}
@@ -440,60 +438,56 @@
@Override
public void onSessionFailure(@NonNull final String packageName,
@NonNull final UserHandle user) {
- enqueueModelUpdateTask(new BaseModelUpdateTask() {
- @Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
- IconCache iconCache = app.getIconCache();
- final IntSet removedIds = new IntSet();
- HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
- boolean isAppArchived = new PackageManagerHelper(
- mApp.getContext()).isAppArchivedForUser(packageName, user);
- synchronized (dataModel) {
- if (isAppArchived) {
- // Remove package icon cache entry for archived app in case of a session
- // failure.
- mApp.getIconCache().remove(
- new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
- user);
- }
+ enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+ IconCache iconCache = mApp.getIconCache();
+ final IntSet removedIds = new IntSet();
+ HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
+ boolean isAppArchived = PackageManagerHelper.INSTANCE.get(mApp.getContext())
+ .isAppArchivedForUser(packageName, user);
+ synchronized (dataModel) {
+ if (isAppArchived) {
+ // Remove package icon cache entry for archived app in case of a session
+ // failure.
+ mApp.getIconCache().remove(
+ new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+ user);
+ }
- for (ItemInfo info : dataModel.itemsIdMap) {
- if (info instanceof WorkspaceItemInfo
- && ((WorkspaceItemInfo) info).hasPromiseIconUi()
- && user.equals(info.user)
- && info.getIntent() != null) {
- if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
- removedIds.add(info.id);
- }
- if (((WorkspaceItemInfo) info).isArchived()) {
- WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
- // Refresh icons on the workspace for archived apps.
- iconCache.getTitleAndIcon(workspaceItem,
- workspaceItem.usingLowResIcon());
- archivedWorkspaceItemsToCacheRefresh.add(workspaceItem);
- }
+ for (ItemInfo info : dataModel.itemsIdMap) {
+ if (info instanceof WorkspaceItemInfo
+ && ((WorkspaceItemInfo) info).hasPromiseIconUi()
+ && user.equals(info.user)
+ && info.getIntent() != null) {
+ if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
+ removedIds.add(info.id);
+ }
+ if (((WorkspaceItemInfo) info).isArchived()) {
+ WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
+ // Refresh icons on the workspace for archived apps.
+ iconCache.getTitleAndIcon(workspaceItem,
+ workspaceItem.usingLowResIcon());
+ archivedWorkspaceItemsToCacheRefresh.add(workspaceItem);
}
}
-
- if (isAppArchived) {
- apps.updateIconsAndLabels(new HashSet<>(List.of(packageName)), user);
- }
}
- if (!removedIds.isEmpty()) {
- deleteAndBindComponentsRemoved(
- ItemInfoMatcher.ofItemIds(removedIds),
- "removed because install session failed");
- }
- if (!archivedWorkspaceItemsToCacheRefresh.isEmpty()) {
- bindUpdatedWorkspaceItems(
- archivedWorkspaceItemsToCacheRefresh.stream().toList());
- }
if (isAppArchived) {
- bindApplicationsIfNeeded();
+ apps.updateIconsAndLabels(new HashSet<>(List.of(packageName)), user);
}
}
+
+ if (!removedIds.isEmpty()) {
+ taskController.deleteAndBindComponentsRemoved(
+ ItemInfoMatcher.ofItemIds(removedIds),
+ "removed because install session failed");
+ }
+ if (!archivedWorkspaceItemsToCacheRefresh.isEmpty()) {
+ taskController.bindUpdatedWorkspaceItems(
+ archivedWorkspaceItemsToCacheRefresh.stream().toList());
+ }
+ if (isAppArchived) {
+ taskController.bindApplicationsIfNeeded();
+ }
});
}
@@ -583,13 +577,9 @@
*/
public void onWidgetLabelsUpdated(@NonNull final HashSet<String> updatedPackages,
@NonNull final UserHandle user) {
- enqueueModelUpdateTask(new BaseModelUpdateTask() {
- @Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
- dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, app);
- bindUpdatedWidgets(dataModel);
- }
+ enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+ dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, mApp);
+ taskController.bindUpdatedWidgets(dataModel);
});
}
@@ -597,8 +587,15 @@
if (mModelDestroyed) {
return;
}
- task.init(mApp, this, mBgDataModel, mBgAllAppsList, MAIN_EXECUTOR);
- MODEL_EXECUTOR.execute(task);
+ MODEL_EXECUTOR.execute(() -> {
+ if (!isModelLoaded()) {
+ // Loader has not yet run.
+ return;
+ }
+ ModelTaskController controller = new ModelTaskController(
+ mApp, mBgDataModel, mBgAllAppsList, this, MAIN_EXECUTOR);
+ task.execute(controller, mBgDataModel, mBgAllAppsList);
+ });
}
/**
@@ -610,18 +607,10 @@
void execute(@NonNull Callbacks callbacks);
}
- /**
- * A runnable which changes/updates the data model of the launcher based on certain events.
- */
- public interface ModelUpdateTask extends Runnable {
+ public interface ModelUpdateTask {
- /**
- * Called before the task is posted to initialize the internal state.
- */
- void init(@NonNull LauncherAppState app, @NonNull LauncherModel model,
- @NonNull BgDataModel dataModel, @NonNull AllAppsList allAppsList,
- @NonNull Executor uiExecutor);
-
+ void execute(@NonNull ModelTaskController taskController,
+ @NonNull BgDataModel dataModel, @NonNull AllAppsList apps);
}
public void updateAndBindWorkspaceItem(@NonNull final WorkspaceItemInfo si,
@@ -638,27 +627,19 @@
*/
public void updateAndBindWorkspaceItem(
@NonNull final Supplier<WorkspaceItemInfo> itemProvider) {
- enqueueModelUpdateTask(new BaseModelUpdateTask() {
- @Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
- WorkspaceItemInfo info = itemProvider.get();
- getModelWriter().updateItemInDatabase(info);
- ArrayList<WorkspaceItemInfo> update = new ArrayList<>();
- update.add(info);
- bindUpdatedWorkspaceItems(update);
- }
+ enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+ WorkspaceItemInfo info = itemProvider.get();
+ taskController.getModelWriter().updateItemInDatabase(info);
+ ArrayList<WorkspaceItemInfo> update = new ArrayList<>();
+ update.add(info);
+ taskController.bindUpdatedWorkspaceItems(update);
});
}
public void refreshAndBindWidgetsAndShortcuts(@Nullable final PackageUserKey packageUser) {
- enqueueModelUpdateTask(new BaseModelUpdateTask() {
- @Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
- dataModel.widgetsModel.update(app, packageUser);
- bindUpdatedWidgets(dataModel);
- }
+ enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+ dataModel.widgetsModel.update(taskController.getApp(), packageUser);
+ taskController.bindUpdatedWidgets(dataModel);
});
}
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 80a8cea..13181e8 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -30,6 +30,7 @@
import com.android.launcher3.states.RotationHelper
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.MainThreadInitializedObject
+import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.Themes
/**
@@ -37,7 +38,7 @@
*
* TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods.
*/
-class LauncherPrefs(private val encryptedContext: Context) {
+class LauncherPrefs(private val encryptedContext: Context) : SafeCloseable {
private val deviceProtectedStorageContext =
encryptedContext.createDeviceProtectedStorageContext()
@@ -242,6 +243,8 @@
}
}
+ override fun close() {}
+
companion object {
@VisibleForTesting const val BOOT_AWARE_PREFS_KEY = "boot_aware_prefs"
@@ -250,6 +253,7 @@
@JvmStatic fun get(context: Context): LauncherPrefs = INSTANCE.get(context)
const val TASKBAR_PINNING_KEY = "TASKBAR_PINNING_KEY"
+ const val TASKBAR_PINNING_DESKTOP_MODE_KEY = "TASKBAR_PINNING_DESKTOP_MODE_KEY"
const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
@JvmField
val ICON_STATE = nonRestorableItem("pref_icon_shape_path", "", EncryptionType.ENCRYPTED)
@@ -269,6 +273,9 @@
@JvmField
val TASKBAR_PINNING =
backedUpItem(TASKBAR_PINNING_KEY, false, EncryptionType.DEVICE_PROTECTED)
+ @JvmField
+ val TASKBAR_PINNING_IN_DESKTOP_MODE =
+ backedUpItem(TASKBAR_PINNING_DESKTOP_MODE_KEY, true, EncryptionType.DEVICE_PROTECTED)
@JvmField
val DEVICE_TYPE =
@@ -317,11 +324,6 @@
@JvmField
val RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN =
backedUpItem("launcher.reconfigurable_widget_education_tip_seen", false)
- @JvmField
- val WIDGETS_EDUCATION_DIALOG_SEEN =
- backedUpItem("launcher.widgets_education_dialog_seen", false)
- @JvmField
- val WIDGETS_EDUCATION_TIP_SEEN = backedUpItem("launcher.widgets_education_tip_seen", false)
@JvmStatic
fun <T> backedUpItem(
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 4e0ba62..6e2d357 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -48,11 +48,11 @@
*/
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
- if (appState == null || !appState.getModel().isModelLoaded()) {
- return;
- }
- appState.getModel().dumpState("", fd, writer, args);
+ LauncherAppState.INSTANCE.executeIfCreated(appState -> {
+ if (appState.getModel().isModelLoaded()) {
+ appState.getModel().dumpState("", fd, writer, args);
+ }
+ });
}
@Override
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index 3d7e11e..9944ef6 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -19,7 +19,6 @@
import android.content.Context;
import com.android.launcher3.graphics.BitmapCreationCheck;
-import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -36,7 +35,6 @@
protected void init(Context context) {
FileLog.setDir(context.getApplicationContext().getFilesDir());
- IconShape.init(context);
if (BitmapCreationCheck.ENABLED) {
BitmapCreationCheck.startTracking(context);
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index f582be0..7d6d154 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -4,11 +4,12 @@
import android.os.Build
import android.os.Trace
import androidx.annotation.UiThread
+import com.android.launcher3.Flags.enableSmartspaceRemovalToggle
import com.android.launcher3.LauncherConstants.TraceEvents
+import com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET
import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
import com.android.launcher3.allapps.AllAppsStore
import com.android.launcher3.config.FeatureFlags
-import com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget
import com.android.launcher3.model.BgDataModel
import com.android.launcher3.model.StringCache
import com.android.launcher3.model.data.AppInfo
@@ -34,7 +35,7 @@
var pagesToBindSynchronously = LIntSet()
private var isFirstPagePinnedItemEnabled =
- (BuildConfig.QSB_ON_FIRST_SCREEN && !FeatureFlags.ENABLE_SMARTSPACE_REMOVAL.get())
+ (BuildConfig.QSB_ON_FIRST_SCREEN && !enableSmartspaceRemovalToggle())
var stringCache: StringCache? = null
@@ -314,16 +315,16 @@
)
val firstScreenPosition = 0
if (
- (FeatureFlags.QSB_ON_FIRST_SCREEN &&
- isFirstPagePinnedItemEnabled &&
- !shouldShowFirstPageWidget()) &&
+ (isFirstPagePinnedItemEnabled &&
+ !SHOULD_SHOW_FIRST_PAGE_WIDGET) &&
orderedScreenIds.indexOf(FIRST_SCREEN_ID) != firstScreenPosition
) {
orderedScreenIds.removeValue(FIRST_SCREEN_ID)
orderedScreenIds.add(firstScreenPosition, FIRST_SCREEN_ID)
} else if (
- (!FeatureFlags.QSB_ON_FIRST_SCREEN && !isFirstPagePinnedItemEnabled ||
- shouldShowFirstPageWidget()) && orderedScreenIds.isEmpty
+ (!isFirstPagePinnedItemEnabled ||
+ SHOULD_SHOW_FIRST_PAGE_WIDGET)
+ && orderedScreenIds.isEmpty
) {
// If there are no screens, we need to have an empty screen
launcher.workspace.addExtraEmptyScreens()
@@ -379,9 +380,8 @@
}
orderedScreenIds
.filterNot { screenId ->
- FeatureFlags.QSB_ON_FIRST_SCREEN &&
isFirstPagePinnedItemEnabled &&
- !FeatureFlags.shouldShowFirstPageWidget() &&
+ !SHOULD_SHOW_FIRST_PAGE_WIDGET &&
screenId == WorkspaceLayoutManager.FIRST_SCREEN_ID
}
.forEach { screenId ->
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 1c23644..365fbd3 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -485,7 +485,10 @@
super.onVisibilityAggregated(isVisible);
}
- protected boolean isPageInTransition() {
+ /**
+ * Returns true if the page is in the middle of transition to another page
+ */
+ public boolean isPageInTransition() {
return mIsPageInTransition;
}
@@ -785,7 +788,7 @@
if (mScroller.isFinished() && pageScrollChanged) {
// TODO(b/246283207): Remove logging once root cause of flake detected.
if (Utilities.isRunningInTestHarness() && !(this instanceof Workspace)) {
- Log.d("b/246283207", this.getClass().getSimpleName() + "#onLayout() -> "
+ Log.d("b/246283207", TAG + "#onLayout() -> "
+ "if(mScroller.isFinished() && pageScrollChanged) -> getNextPage(): "
+ getNextPage() + ", getScrollForPage(getNextPage()): "
+ getScrollForPage(getNextPage()));
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 1362586..0a4fb73 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -362,7 +362,7 @@
public void onLauncherResume() {
// We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well.
- if (new PackageManagerHelper(mContext).getApplicationInfo(mPackageName,
+ if (PackageManagerHelper.INSTANCE.get(mContext).getApplicationInfo(mPackageName,
mDragObject.dragInfo.user, PackageManager.MATCH_UNINSTALLED_PACKAGES) == null) {
mDragObject.dragSource = mOriginal;
mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 2b886e4..19a3002 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -18,6 +18,8 @@
import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
+import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
+import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -68,6 +70,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewGroup;
import android.view.animation.Interpolator;
import androidx.annotation.ChecksSdkIntAtLeast;
@@ -102,6 +105,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -130,6 +134,10 @@
@ChecksSdkIntAtLeast(api = VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "U")
public static final boolean ATLEAST_U = Build.VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE;
+ @ChecksSdkIntAtLeast(api = VERSION_CODES.VANILLA_ICE_CREAM, codename = "V")
+ public static final boolean ATLEAST_V = Build.VERSION.SDK_INT
+ >= VERSION_CODES.VANILLA_ICE_CREAM;
+
/**
* Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}.
*/
@@ -148,6 +156,9 @@
public static final int TRANSLATE_LEFT = 2;
public static final int TRANSLATE_RIGHT = 3;
+ public static final boolean SHOULD_SHOW_FIRST_PAGE_WIDGET =
+ enableSmartspaceAsAWidget() && WIDGET_ON_FIRST_SCREEN;
+
@IntDef({TRANSLATE_UP, TRANSLATE_DOWN, TRANSLATE_LEFT, TRANSLATE_RIGHT})
public @interface AdjustmentDirection{}
@@ -634,7 +645,7 @@
} else {
// Wrap the main icon in AID
try (LauncherIcons li = LauncherIcons.obtain(context)) {
- result = li.wrapToAdaptiveIcon(mainIcon);
+ result = li.wrapToAdaptiveIcon(mainIcon, null);
}
}
if (result == null) {
@@ -830,4 +841,27 @@
// No-Op
}
}
+
+ /**
+ * Does a depth-first search through the View hierarchy starting at root, to find a view that
+ * matches the predicate. Returns null if no View was found. View has a findViewByPredicate
+ * member function but it is currently a @hide API.
+ */
+ @Nullable
+ public static <T extends View> T findViewByPredicate(@NonNull View root,
+ @NonNull Predicate<View> predicate) {
+ if (predicate.test(root)) {
+ return (T) root;
+ }
+ if (root instanceof ViewGroup parent) {
+ int count = parent.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View view = findViewByPredicate(parent.getChildAt(i), predicate);
+ if (view != null) {
+ return (T) view;
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0fc3211..584d089 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -28,10 +29,9 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
@@ -126,7 +126,6 @@
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetManagerHelper;
-import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
import com.android.launcher3.widget.util.WidgetSizes;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
@@ -600,7 +599,7 @@
public void bindAndInitFirstWorkspaceScreen() {
if ((!FeatureFlags.QSB_ON_FIRST_SCREEN
|| !mLauncher.getIsFirstPagePinnedItemEnabled())
- || shouldShowFirstPageWidget()) {
+ || SHOULD_SHOW_FIRST_PAGE_WIDGET) {
mFirstPagePinnedItem = null;
return;
}
@@ -642,7 +641,7 @@
mWorkspaceScreens.clear();
// Ensure that the first page is always present
- if (!ENABLE_SMARTSPACE_REMOVAL.get()) {
+ if (!enableSmartspaceRemovalToggle()) {
bindAndInitFirstWorkspaceScreen();
}
@@ -811,7 +810,7 @@
// We don't want to remove the first screen even if it's empty because that's where
// first page pinned item would go if it gets turned back on.
- if (ENABLE_SMARTSPACE_REMOVAL.get() && screenId == FIRST_SCREEN_ID) {
+ if (enableSmartspaceRemovalToggle() && screenId == FIRST_SCREEN_ID) {
continue;
}
@@ -1040,7 +1039,7 @@
CellLayout cl = mWorkspaceScreens.valueAt(i);
// FIRST_SCREEN_ID can never be removed.
if (((!FeatureFlags.QSB_ON_FIRST_SCREEN
- || shouldShowFirstPageWidget())
+ || SHOULD_SHOW_FIRST_PAGE_WIDGET)
|| id > FIRST_SCREEN_ID)
&& cl.getShortcutsAndWidgets().getChildCount() == 0) {
removeScreens.add(id);
@@ -1744,9 +1743,6 @@
final DragView dv;
if (contentView instanceof View) {
- if (contentView instanceof LauncherAppWidgetHostView) {
- mDragController.addDragListener(new AppWidgetHostViewDragListener(mLauncher));
- }
dv = mDragController.startDrag(
contentView,
draggableView,
@@ -1955,7 +1951,7 @@
// In order to keep everything continuous, we hand off the currently rendered
// folder background to the newly created icon. This preserves animation state.
fi.setFolderBackground(mFolderCreateBg);
- mFolderCreateBg = new PreviewBackground();
+ mFolderCreateBg = new PreviewBackground(getContext());
fi.performCreateAnimation(destInfo, v, sourceInfo, d, folderLocation, scale);
} else {
fi.prepareCreateAnimation(v);
@@ -2670,7 +2666,7 @@
boolean userFolderPending = willCreateUserFolder(info, mDragOverView, false);
if (mDragMode == DRAG_MODE_NONE && userFolderPending) {
- mFolderCreateBg = new PreviewBackground();
+ mFolderCreateBg = new PreviewBackground(getContext());
mFolderCreateBg.setup(mLauncher, mLauncher, null,
mDragOverView.getMeasuredWidth(), mDragOverView.getPaddingTop());
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 8026d4a..0792641 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Flags.enableExpandingPauseWorkButton;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
+import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.WORK;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
@@ -470,8 +471,9 @@
* @param exitSearch Whether to force exit the search state and return to A-Z apps list.
*/
public void reset(boolean animate, boolean exitSearch) {
+ // Scroll Main and Work RV to top. Search RV is done in `resetSearch`.
for (int i = 0; i < mAH.size(); i++) {
- if (mAH.get(i).mRecyclerView != null) {
+ if (i != SEARCH && mAH.get(i).mRecyclerView != null) {
mAH.get(i).mRecyclerView.scrollToTop();
}
}
@@ -485,10 +487,8 @@
// Reset the base recycler view after transitioning home.
updateHeaderScroll(0);
if (exitSearch) {
- // Reset the search bar after transitioning home.
+ // Reset the search bar and search RV after transitioning home.
MAIN_EXECUTOR.getHandler().post(mSearchUiManager::resetSearch);
- // Animate to A-Z with 0 time to reset the animation with proper state management.
- animateToSearchState(false, 0);
}
if (isSearching()) {
mWorkManager.reset();
@@ -499,18 +499,15 @@
* Exits search and returns to A-Z apps list. Scroll to the private space header.
*/
public void resetAndScrollToPrivateSpaceHeader() {
- if (mTouchHandler != null) {
- mTouchHandler.endFastScrolling();
- }
-
- // Reset the base recycler view after transitioning home.
- updateHeaderScroll(0);
-
// Animate to A-Z with 0 time to reset the animation with proper state management.
+ // We can't rely on `animateToSearchState` with delay inside `resetSearch` because that will
+ // conflict with following scrolling to bottom, so we need it with 0 time here.
animateToSearchState(false, 0);
MAIN_EXECUTOR.getHandler().post(() -> {
// Reset the search bar after transitioning home.
+ // When `resetSearch` is called after `animateToSearchState` is finished, the inside
+ // `animateToSearchState` with delay is a just no-op and return early.
mSearchUiManager.resetSearch();
// Switch to the main tab
switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 564daf1..1b0ad04 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -294,7 +294,9 @@
private void onScaleProgressChanged() {
final float scaleProgress = mAllAppScale.value;
SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
- mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+ if (!mLauncher.getAppsView().isSearching() || !mLauncher.getDeviceProfile().isTablet) {
+ mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+ }
AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 60df7c5..a810331 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT;
import android.content.Context;
-import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
@@ -362,7 +361,7 @@
// Split of private space apps into user-installed and system apps.
Map<Boolean, List<AppInfo>> split = mPrivateApps.stream()
.collect(Collectors.partitioningBy(mPrivateProviderManager
- .splitIntoUserInstalledAndSystemApps()));
+ .splitIntoUserInstalledAndSystemApps(mActivityContext)));
// TODO(b/329688630): switch to the pulled LayoutStaticSnapshot atom
mActivityContext
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index a21d7be..16630967 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -44,7 +44,6 @@
import com.android.launcher3.R;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.views.ActivityContext;
/**
@@ -273,8 +272,8 @@
privateProfileManager.isPrivateSpaceItem(adapterItem);
if (icon.getAlpha() == 0 || icon.getAlpha() == 1) {
icon.setAlpha(isPrivateSpaceItem
- && privateProfileManager.getAnimationScrolling()
- && privateProfileManager.getAnimate()
+ && (privateProfileManager.getAnimationScrolling() ||
+ privateProfileManager.getAnimate())
&& privateProfileManager.getCurrentState() == STATE_ENABLED
? 0 : 1);
}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 38fe138..53f9cfc 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -20,7 +20,6 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
@@ -28,8 +27,12 @@
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
@@ -80,9 +83,7 @@
import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.function.Predicate;
/**
@@ -91,7 +92,15 @@
*/
public class PrivateProfileManager extends UserProfileManager {
private static final int EXPAND_COLLAPSE_DURATION = 800;
- private static final int SETTINGS_OPACITY_DURATION = 160;
+ private static final int SETTINGS_OPACITY_DURATION = 400;
+ private static final int TEXT_UNLOCK_OPACITY_DURATION = 300;
+ private static final int TEXT_LOCK_OPACITY_DURATION = 50;
+ private static final int APP_OPACITY_DURATION = 400;
+ private static final int APP_OPACITY_DELAY = 400;
+ private static final int SETTINGS_AND_LOCK_GROUP_TRANSITION_DELAY = 400;
+ private static final int SETTINGS_OPACITY_DELAY = 400;
+ private static final int LOCK_TEXT_OPACITY_DELAY = 500;
+ private static final int NO_DELAY = 0;
private final ActivityAllAppsContainerView<?> mAllApps;
private final Predicate<UserHandle> mPrivateProfileMatcher;
private final int mPsHeaderHeight;
@@ -105,7 +114,6 @@
}
}
};
- private Set<String> mPreInstalledSystemPackages = new HashSet<>();
private Intent mAppInstallerIntent = new Intent();
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
private boolean mPrivateSpaceSettingsAvailable;
@@ -115,6 +123,8 @@
private Runnable mOnPSHeaderAdded;
@Nullable
private RelativeLayout mPSHeader;
+ private final String mLockedStateContentDesc;
+ private final String mUnLockedStateContentDesc;
public PrivateProfileManager(UserManager userManager,
ActivityAllAppsContainerView<?> allApps,
@@ -128,6 +138,10 @@
UI_HELPER_EXECUTOR.post(() -> initializeInBackgroundThread(appContext));
mPsHeaderHeight = mAllApps.getContext().getResources().getDimensionPixelSize(
R.dimen.ps_header_height);
+ mLockedStateContentDesc = mAllApps.getContext()
+ .getString(R.string.ps_container_lock_button_content_description);
+ mUnLockedStateContentDesc = mAllApps.getContext()
+ .getString(R.string.ps_container_unlock_button_content_description);
}
/** Adds Private Space Header to the layout. */
@@ -264,8 +278,6 @@
ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(appContext);
UserHandle profileUser = getProfileUser();
if (profileUser != null) {
- mPreInstalledSystemPackages = new HashSet<>(
- apiWrapper.getPreInstalledSystemPackages(profileUser));
mAppInstallerIntent = apiWrapper
.getAppMarketActivityIntent(BuildConfig.APPLICATION_ID, profileUser);
}
@@ -349,10 +361,12 @@
* Splits private apps into user installed and system apps.
* When the list of system apps is empty, all apps are treated as system.
*/
- public Predicate<AppInfo> splitIntoUserInstalledAndSystemApps() {
- return appInfo -> !mPreInstalledSystemPackages.isEmpty()
+ public Predicate<AppInfo> splitIntoUserInstalledAndSystemApps(Context context) {
+ List<String> preInstallApps = UserCache.getInstance(context)
+ .getPreInstallApps(getProfileUser());
+ return appInfo -> !preInstallApps.isEmpty()
&& (appInfo.componentName == null
- || !(mPreInstalledSystemPackages.contains(appInfo.componentName.getPackageName())));
+ || !(preInstallApps.contains(appInfo.componentName.getPackageName())));
}
/** Add Private Space Header view elements based upon {@link UserProfileState} */
@@ -401,11 +415,13 @@
lockText.setVisibility(VISIBLE);
lockButton.setVisibility(VISIBLE);
lockButton.setOnClickListener(view -> lockingAction(/* lock */ true));
+ lockButton.setContentDescription(mUnLockedStateContentDesc);
}
case STATE_DISABLED -> {
lockText.setVisibility(GONE);
lockButton.setVisibility(VISIBLE);
lockButton.setOnClickListener(view -> lockingAction(/* lock */ false));
+ lockButton.setContentDescription(mLockedStateContentDesc);
}
default -> lockButton.setVisibility(GONE);
}
@@ -415,9 +431,14 @@
if (getCurrentState() == STATE_DISABLED) {
header.setOnClickListener(view -> lockingAction(/* lock */ false));
header.setClickable(true);
+ // Add header as accessibility target when disabled.
+ header.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ header.setContentDescription(mLockedStateContentDesc);
} else {
header.setOnClickListener(null);
header.setClickable(false);
+ // Remove header from accessibility target when enabled.
+ header.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
}
@@ -435,7 +456,6 @@
if (getCurrentState() == STATE_ENABLED
&& isPrivateSpaceSettingsAvailable()) {
settingsButton.setVisibility(VISIBLE);
- settingsButton.setAlpha(1f);
settingsButton.setOnClickListener(
view -> {
logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
@@ -580,7 +600,9 @@
List<BaseAllAppsAdapter.AdapterItem> allAppsAdapterItems =
mAllApps.getActiveRecyclerView().getApps().getAdapterItems();
ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
- alphaAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+ alphaAnim.setDuration(APP_OPACITY_DURATION)
+ .setStartDelay(isExpanding ? APP_OPACITY_DELAY : NO_DELAY);
+ alphaAnim.setInterpolator(Interpolators.LINEAR);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
@@ -616,27 +638,39 @@
return;
}
ViewGroup settingsAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
- ViewGroup lockButton = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
if (settingsAndLockGroup.getLayoutTransition() == null) {
// Set a new transition if the current ViewGroup does not already contain one as each
// transition should only happen once when applied.
enableLayoutTransition(settingsAndLockGroup);
}
+ settingsAndLockGroup.getLayoutTransition().setStartDelay(
+ LayoutTransition.CHANGING,
+ expand ? SETTINGS_AND_LOCK_GROUP_TRANSITION_DELAY : NO_DELAY);
PropertySetter headerSetter = new AnimatedPropertySetter();
- ImageButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
- updateSettingsGearAlpha(settingsButton, expand, headerSetter);
+ headerSetter.add(updateSettingsGearAlpha(expand));
+ headerSetter.add(updateLockTextAlpha(expand));
AnimatorSet animatorSet = headerSetter.buildAnim();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
+ mStatsLogManager.logger().sendToInteractionJankMonitor(
+ expand
+ ? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN
+ : LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN,
+ mAllApps.getActiveRecyclerView());
// Animate the collapsing of the text at the same time while updating lock button.
- lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
+ mPSHeader.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
setAnimationRunning(true);
}
});
animatorSet.addListener(forEndCallback(() -> {
setAnimationRunning(false);
getMainRecyclerView().setChildAttachedConsumer(child -> child.setAlpha(1));
+ mStatsLogManager.logger().sendToInteractionJankMonitor(
+ expand
+ ? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END
+ : LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END,
+ mAllApps.getActiveRecyclerView());
if (!expand) {
// Call onAppsUpdated() because it may be canceled when this animation occurs.
mAllApps.getPersonalAppList().onAppsUpdated();
@@ -686,6 +720,8 @@
LayoutTransition settingsAndLockTransition = new LayoutTransition();
settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
+ settingsAndLockTransition.setInterpolator(LayoutTransition.CHANGING,
+ Interpolators.STANDARD);
settingsAndLockTransition.addTransitionListener(new LayoutTransition.TransitionListener() {
@Override
public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
@@ -702,11 +738,44 @@
}
/** Change the settings gear alpha when expanded or collapsed. */
- private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
- PropertySetter setter) {
- float toAlpha = expand ? 1 : 0;
- setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
- .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
+ private ValueAnimator updateSettingsGearAlpha(boolean expand) {
+ if (mPSHeader == null) {
+ return new ValueAnimator();
+ }
+ float from = expand ? 0 : 1;
+ float to = expand ? 1 : 0;
+ ValueAnimator settingsAlphaAnim = ObjectAnimator.ofFloat(from, to);
+ settingsAlphaAnim.setDuration(SETTINGS_OPACITY_DURATION);
+ settingsAlphaAnim.setStartDelay(expand ? SETTINGS_OPACITY_DELAY : NO_DELAY);
+ settingsAlphaAnim.setInterpolator(Interpolators.LINEAR);
+ settingsAlphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mPSHeader.findViewById(R.id.ps_settings_button)
+ .setAlpha((float) valueAnimator.getAnimatedValue());
+ }
+ });
+ return settingsAlphaAnim;
+ }
+
+ private ValueAnimator updateLockTextAlpha(boolean expand) {
+ if (mPSHeader == null) {
+ return new ValueAnimator();
+ }
+ float from = expand ? 0 : 1;
+ float to = expand ? 1 : 0;
+ ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
+ alphaAnim.setDuration(expand ? TEXT_UNLOCK_OPACITY_DURATION : TEXT_LOCK_OPACITY_DURATION);
+ alphaAnim.setStartDelay(expand ? LOCK_TEXT_OPACITY_DELAY : NO_DELAY);
+ alphaAnim.setInterpolator(Interpolators.LINEAR);
+ alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mPSHeader.findViewById(R.id.lock_text).setAlpha(
+ (float) valueAnimator.getAnimatedValue());
+ }
+ });
+ return alphaAnim;
}
void expandPrivateSpace() {
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 6a1f37a..3351ee3 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -52,11 +52,11 @@
@Retention(RetentionPolicy.SOURCE)
public @interface UserProfileState { }
+ protected final StatsLogManager mStatsLogManager;
@UserProfileState
private int mCurrentState;
private final UserManager mUserManager;
- private final StatsLogManager mStatsLogManager;
private final UserCache mUserCache;
protected UserProfileManager(UserManager userManager,
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 19c3ebe..ec45415 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -31,6 +31,7 @@
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
import com.android.launcher3.views.ActivityContext;
@@ -143,7 +144,7 @@
@Override
public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus) {
+ if (!hasFocus && !FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
mInput.hideKeyboard();
}
}
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index ab47097..8121d2a 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -22,13 +22,9 @@
import android.os.Handler;
import androidx.annotation.AnyThread;
-import androidx.annotation.NonNull;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
-import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
@@ -67,16 +63,12 @@
@Override
public void doSearch(String query, SearchCallback<AdapterItem> callback) {
- mAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() {
- @Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
- ArrayList<AdapterItem> result = getTitleMatchResult(apps.data, query);
- if (mAddNoResultsMessage && result.isEmpty()) {
- result.add(getEmptyMessageAdapterItem(query));
- }
- mResultHandler.post(() -> callback.onSearchResult(query, result));
+ mAppState.getModel().enqueueModelUpdateTask((taskController, dataModel, apps) -> {
+ ArrayList<AdapterItem> result = getTitleMatchResult(apps.data, query);
+ if (mAddNoResultsMessage && result.isEmpty()) {
+ result.add(getEmptyMessageAdapterItem(query));
}
+ mResultHandler.post(() -> callback.onSearchResult(query, result));
});
}
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 1f73241..32445ec 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -30,6 +30,8 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Reorderable;
@@ -85,6 +87,11 @@
: activity.getLayoutInflater();
AppPairIcon icon = (AppPairIcon) inflater.inflate(resId, group, false);
+ if (Flags.enableFocusOutline() && activity instanceof Launcher) {
+ icon.setOnFocusChangeListener(((Launcher) activity).getFocusHandler());
+ icon.setDefaultFocusHighlightEnabled(false);
+ }
+
// Sort contents, so that left-hand app comes first
appPairInfo.getContents().sort(Comparator.comparingInt(a -> a.rank));
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 3badc64..e1a7d66 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -16,7 +16,6 @@
package com.android.launcher3.config;
-import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.config.FeatureFlags.BooleanFlag.DISABLED;
import static com.android.launcher3.config.FeatureFlags.BooleanFlag.ENABLED;
import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
@@ -135,17 +134,6 @@
"MULTI_SELECT_EDIT_MODE", DISABLED, "Enable new multi-select edit mode "
+ "for home screen");
- public static final BooleanFlag SMARTSPACE_AS_A_WIDGET = getDebugFlag(299181941,
- "SMARTSPACE_AS_A_WIDGET", DISABLED, "Enable SmartSpace as a widget");
-
- public static boolean shouldShowFirstPageWidget() {
- return SMARTSPACE_AS_A_WIDGET.get() && WIDGET_ON_FIRST_SCREEN;
- }
-
- public static final BooleanFlag ENABLE_SMARTSPACE_REMOVAL = getDebugFlag(290799975,
- "ENABLE_SMARTSPACE_REMOVAL", DISABLED, "Enable SmartSpace removal for "
- + "home screen");
-
// TODO(Block 11): Clean up flags
public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
"FOLDABLE_SINGLE_PAGE", DISABLED, "Use a single page for the workspace");
@@ -215,9 +203,6 @@
"ENABLE_EXPANDING_PAUSE_WORK_BUTTON", DISABLED,
"Expand and collapse pause work button while scrolling");
- public static final BooleanFlag COLLECT_SEARCH_HISTORY = getReleaseFlag(270391455,
- "COLLECT_SEARCH_HISTORY", DISABLED, "Allow launcher to collect search history for log");
-
// Aconfig migration complete for ENABLE_TWOLINE_ALLAPPS.
public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
"ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 05fdcef..ec0a222 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -162,7 +162,7 @@
finish();
return;
}
- ApplicationInfo info = new PackageManagerHelper(this)
+ ApplicationInfo info = PackageManagerHelper.INSTANCE.get(this)
.getApplicationInfo(targetApp.packageName, targetApp.user, 0);
if (info == null) {
finish();
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 7a2ec97..7ef3209 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.BubbleTextView.TEXT_ALPHA_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
-import static com.android.launcher3.graphics.IconShape.getShape;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -45,6 +44,8 @@
import com.android.launcher3.anim.PropertyResetListener;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
+import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.graphics.IconShape.ShapeDelegate;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
@@ -233,8 +234,9 @@
}
play(a, getAnimator(mFolder.mFooter, ALPHA, 0, 1f), footerStartDelay, footerAlphaDuration);
+ ShapeDelegate shapeDelegate = IconShape.INSTANCE.get(mContext).getShape();
// Create reveal animator for the folder background
- play(a, getShape().createRevealAnimator(
+ play(a, shapeDelegate.createRevealAnimator(
mFolder, startRect, endRect, finalRadius, !mIsOpening));
// Create reveal animator for the folder content (capture the top 4 icons 2x2)
@@ -246,10 +248,9 @@
int left = mContent.getPaddingLeft() + page * lp.width;
Rect contentStart = new Rect(left, 0, left + width, height);
Rect contentEnd = new Rect(left, 0, left + lp.width, lp.height);
- play(a, getShape().createRevealAnimator(
+ play(a, shapeDelegate.createRevealAnimator(
mFolder.getContent(), contentStart, contentEnd, finalRadius, !mIsOpening));
-
// Fade in the folder name, as the text can overlap the icons when grid size is small.
mFolder.mFolderName.setAlpha(mIsOpening ? 0f : 1f);
play(a, getAnimator(mFolder.mFolderName, View.ALPHA, 0, 1),
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 4d88b68..00636a3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -112,7 +112,7 @@
@Thunk BubbleTextView mFolderName;
- PreviewBackground mBackground = new PreviewBackground();
+ PreviewBackground mBackground = new PreviewBackground(getContext());
private boolean mBackgroundIsVisible = true;
FolderGridOrganizer mPreviewVerifier;
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 5d2bb3a..be5f8f7 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -28,11 +28,12 @@
import androidx.annotation.WorkerThread;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.ModelTaskController;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.CollectionInfo;
@@ -191,10 +192,11 @@
nameInfos.setLabel(labels.length - 1, label, 1.0f);
}
- private class FolderNameWorker extends BaseModelUpdateTask {
+ private class FolderNameWorker implements ModelUpdateTask {
+
@Override
- public void execute(@NonNull final LauncherAppState app,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
+ public void execute(@NonNull ModelTaskController taskController,
+ @NonNull BgDataModel dataModel, @NonNull AllAppsList apps) {
mCollectionInfos = dataModel.collections.clone();
mAppInfos = Arrays.asList(apps.copyData());
}
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index ec03803..df41d47 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -19,7 +19,6 @@
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
-import static com.android.launcher3.graphics.IconShape.getShape;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.animation.Animator;
@@ -49,6 +48,8 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.celllayout.DelegatedCellDrawing;
+import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.graphics.IconShape.ShapeDelegate;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
@@ -66,6 +67,7 @@
@VisibleForTesting protected static final float HOVER_SCALE = 1.1f;
@VisibleForTesting protected static final int HOVER_ANIMATION_DURATION = 300;
+ private final Context mContext;
private final PorterDuffXfermode mShadowPorterDuffXfermode
= new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
private RadialGradient mShadowShader = null;
@@ -138,6 +140,10 @@
}
};
+ public PreviewBackground(Context context) {
+ mContext = context;
+ }
+
/**
* Draws folder background under cell layout
*/
@@ -254,6 +260,10 @@
drawShadow(canvas);
}
+ private ShapeDelegate getShape() {
+ return IconShape.INSTANCE.get(mContext).getShape();
+ }
+
public void drawShadow(Canvas canvas) {
if (!DRAW_SHADOW) {
return;
diff --git a/src/com/android/launcher3/graphics/IconShape.java b/src/com/android/launcher3/graphics/IconShape.java
index f82b07e..5f8f2dc 100644
--- a/src/com/android/launcher3/graphics/IconShape.java
+++ b/src/com/android/launcher3/graphics/IconShape.java
@@ -22,7 +22,6 @@
import android.animation.FloatArrayEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -35,7 +34,6 @@
import android.graphics.Region.Op;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
-import android.os.Build;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.View;
@@ -45,6 +43,8 @@
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.IconNormalizer;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.views.ClipPathView;
import org.xmlpull.v1.XmlPullParser;
@@ -57,38 +57,94 @@
/**
* Abstract representation of the shape of an icon shape
*/
-public abstract class IconShape {
+public final class IconShape implements SafeCloseable {
- private static IconShape sInstance = new Circle();
- private static float sNormalizationScale = ICON_VISIBLE_AREA_FACTOR;
+ public static final MainThreadInitializedObject<IconShape> INSTANCE =
+ new MainThreadInitializedObject<>(IconShape::new);
- public static IconShape getShape() {
- return sInstance;
+
+ private ShapeDelegate mDelegate = new Circle();
+ private float mNormalizationScale = ICON_VISIBLE_AREA_FACTOR;
+
+ private IconShape(Context context) {
+ pickBestShape(context);
}
- public static float getNormalizationScale() {
- return sNormalizationScale;
+ public ShapeDelegate getShape() {
+ return mDelegate;
}
- public boolean enableShapeDetection(){
- return false;
- };
+ public float getNormalizationScale() {
+ return mNormalizationScale;
+ }
- public abstract void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
- Paint paint);
+ @Override
+ public void close() { }
- public abstract void addToPath(Path path, float offsetX, float offsetY, float radius);
+ /**
+ * Initializes the shape which is closest to the {@link AdaptiveIconDrawable}
+ */
+ public void pickBestShape(Context context) {
+ // Pick any large size
+ final int size = 200;
- public abstract <T extends View & ClipPathView> Animator createRevealAnimator(T target,
- Rect startRect, Rect endRect, float endRadius, boolean isReversed);
+ Region full = new Region(0, 0, size, size);
+ Region iconR = new Region();
+ AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
+ new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));
+ drawable.setBounds(0, 0, size, size);
+ iconR.setPath(drawable.getIconMask(), full);
+
+ Path shapePath = new Path();
+ Region shapeR = new Region();
+
+ // Find the shape with minimum area of divergent region.
+ int minArea = Integer.MAX_VALUE;
+ ShapeDelegate closestShape = null;
+ for (ShapeDelegate shape : getAllShapes(context)) {
+ shapePath.reset();
+ shape.addToPath(shapePath, 0, 0, size / 2f);
+ shapeR.setPath(shapePath, full);
+ shapeR.op(iconR, Op.XOR);
+
+ int area = GraphicsUtils.getArea(shapeR);
+ if (area < minArea) {
+ minArea = area;
+ closestShape = shape;
+ }
+ }
+
+ if (closestShape != null) {
+ mDelegate = closestShape;
+ }
+
+ // Initialize shape properties
+ mNormalizationScale = IconNormalizer.normalizeAdaptiveIcon(drawable, size, null);
+ }
+
+
+
+ public interface ShapeDelegate {
+
+ default boolean enableShapeDetection() {
+ return false;
+ }
+
+ void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint paint);
+
+ void addToPath(Path path, float offsetX, float offsetY, float radius);
+
+ <T extends View & ClipPathView> ValueAnimator createRevealAnimator(T target,
+ Rect startRect, Rect endRect, float endRadius, boolean isReversed);
+ }
/**
* Abstract shape where the reveal animation is a derivative of a round rect animation
*/
- private static abstract class SimpleRectShape extends IconShape {
+ private static abstract class SimpleRectShape implements ShapeDelegate {
@Override
- public final <T extends View & ClipPathView> Animator createRevealAnimator(T target,
+ public final <T extends View & ClipPathView> ValueAnimator createRevealAnimator(T target,
Rect startRect, Rect endRect, float endRadius, boolean isReversed) {
return new RoundedRectRevealOutlineProvider(
getStartRadius(startRect), endRadius, startRect, endRect) {
@@ -105,7 +161,7 @@
/**
* Abstract shape which draws using {@link Path}
*/
- private static abstract class PathShape extends IconShape {
+ private static abstract class PathShape implements ShapeDelegate {
private final Path mTmpPath = new Path();
@@ -121,7 +177,7 @@
Rect startRect, Rect endRect, float endRadius, Path outPath);
@Override
- public final <T extends View & ClipPathView> Animator createRevealAnimator(T target,
+ public final <T extends View & ClipPathView> ValueAnimator createRevealAnimator(T target,
Rect startRect, Rect endRect, float endRadius, boolean isReversed) {
Path path = new Path();
AnimatorUpdateListener listener =
@@ -203,7 +259,7 @@
}
}
- public static class RoundedSquare extends SimpleRectShape {
+ private static class RoundedSquare extends SimpleRectShape {
/**
* Ratio of corner radius to half size.
@@ -237,7 +293,7 @@
}
}
- public static class TearDrop extends PathShape {
+ private static class TearDrop extends PathShape {
/**
* Radio of short radius to large radius, based on the shape options defined in the config.
@@ -289,7 +345,7 @@
}
}
- public static class Squircle extends PathShape {
+ private static class Squircle extends PathShape {
/**
* Radio of radius to circle radius, based on the shape options defined in the config.
@@ -375,14 +431,7 @@
}
}
- /**
- * Initializes the shape which is closest to the {@link AdaptiveIconDrawable}
- */
- public static void init(Context context) {
- pickBestShape(context);
- }
-
- private static IconShape getShapeDefinition(String type, float radius) {
+ private static ShapeDelegate getShapeDefinition(String type, float radius) {
switch (type) {
case "Circle":
return new Circle();
@@ -397,8 +446,8 @@
}
}
- private static List<IconShape> getAllShapes(Context context) {
- ArrayList<IconShape> result = new ArrayList<>();
+ private static List<ShapeDelegate> getAllShapes(Context context) {
+ ArrayList<ShapeDelegate> result = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.folder_shapes)) {
// Find the root tag
@@ -416,7 +465,7 @@
if (type == XmlPullParser.START_TAG) {
AttributeSet attrs = Xml.asAttributeSet(parser);
TypedArray a = context.obtainStyledAttributes(attrs, radiusAttr);
- IconShape shape = getShapeDefinition(parser.getName(), a.getFloat(0, 1));
+ ShapeDelegate shape = getShapeDefinition(parser.getName(), a.getFloat(0, 1));
a.recycle();
result.add(shape);
@@ -428,42 +477,4 @@
return result;
}
- @TargetApi(Build.VERSION_CODES.O)
- protected static void pickBestShape(Context context) {
- // Pick any large size
- final int size = 200;
-
- Region full = new Region(0, 0, size, size);
- Region iconR = new Region();
- AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
- new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));
- drawable.setBounds(0, 0, size, size);
- iconR.setPath(drawable.getIconMask(), full);
-
- Path shapePath = new Path();
- Region shapeR = new Region();
-
- // Find the shape with minimum area of divergent region.
- int minArea = Integer.MAX_VALUE;
- IconShape closestShape = null;
- for (IconShape shape : getAllShapes(context)) {
- shapePath.reset();
- shape.addToPath(shapePath, 0, 0, size / 2f);
- shapeR.setPath(shapePath, full);
- shapeR.op(iconR, Op.XOR);
-
- int area = GraphicsUtils.getArea(shapeR);
- if (area < minArea) {
- minArea = area;
- closestShape = shape;
- }
- }
-
- if (closestShape != null) {
- sInstance = closestShape;
- }
-
- // Initialize shape properties
- sNormalizationScale = IconNormalizer.normalizeAdaptiveIcon(drawable, size, null);
- }
}
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 0e4b48e..ae8f1d5 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -24,7 +24,7 @@
import static com.android.launcher3.BubbleTextView.DISPLAY_WORKSPACE;
import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
@@ -66,7 +66,6 @@
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -77,7 +76,6 @@
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.WidgetItem;
@@ -88,14 +86,11 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
-import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.ActivityContext;
@@ -104,7 +99,6 @@
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.LauncherWidgetHolder;
import com.android.launcher3.widget.LocalColorExtractor;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
import com.android.launcher3.widget.util.WidgetSizes;
import java.util.ArrayList;
@@ -112,7 +106,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Utility class for generating the preview of Launcher for a given InvariantDeviceProfile.
@@ -131,47 +124,12 @@
*/
public static class PreviewContext extends SandboxContext {
- private final InvariantDeviceProfile mIdp;
- private final ConcurrentLinkedQueue<LauncherIconsForPreview> mIconPool =
- new ConcurrentLinkedQueue<>();
-
public PreviewContext(Context base, InvariantDeviceProfile idp) {
- super(base, UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
- LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
- CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE,
- WindowManagerProxy.INSTANCE, DisplayController.INSTANCE);
- mIdp = idp;
- mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
- mObjectMap.put(LauncherAppState.INSTANCE,
+ super(base);
+ putObject(InvariantDeviceProfile.INSTANCE, idp);
+ putObject(LauncherAppState.INSTANCE,
new LauncherAppState(this, null /* iconCacheFileName */));
}
-
- /**
- * Creates a new LauncherIcons for the preview, skipping the global pool
- */
- public LauncherIcons newLauncherIcons(Context context) {
- LauncherIconsForPreview launcherIconsForPreview = mIconPool.poll();
- if (launcherIconsForPreview != null) {
- return launcherIconsForPreview;
- }
- return new LauncherIconsForPreview(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize,
- -1 /* poolId */);
- }
-
- private final class LauncherIconsForPreview extends LauncherIcons {
-
- private LauncherIconsForPreview(Context context, int fillResIconDpi, int iconBitmapSize,
- int poolId) {
- super(context, fillResIconDpi, iconBitmapSize, poolId);
- }
-
- @Override
- public void recycle() {
- // Clear any temporary state variables
- clear();
- mIconPool.offer(this);
- }
- }
}
private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>();
@@ -229,10 +187,11 @@
launcherWidgetSpanInfo;
CellLayout firstScreen = mRootView.findViewById(R.id.workspace);
- firstScreen.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingPx.left,
+ firstScreen.setPadding(
+ mDp.workspacePadding.left + mDp.cellLayoutPaddingPx.left,
mDp.workspacePadding.top + mDp.cellLayoutPaddingPx.top,
- (mDp.isTwoPanels ? mDp.cellLayoutBorderSpacePx.x / 2
- : mDp.workspacePadding.right) + mDp.cellLayoutPaddingPx.right,
+ mDp.isTwoPanels ? (mDp.cellLayoutBorderSpacePx.x / 2)
+ : (mDp.workspacePadding.right + mDp.cellLayoutPaddingPx.right),
mDp.workspacePadding.bottom + mDp.cellLayoutPaddingPx.bottom
);
mWorkspaceScreens.put(FIRST_SCREEN_ID, firstScreen);
@@ -240,7 +199,7 @@
if (mDp.isTwoPanels) {
CellLayout rightPanel = mRootView.findViewById(R.id.workspace_right);
rightPanel.setPadding(
- mDp.cellLayoutBorderSpacePx.x / 2 + mDp.cellLayoutPaddingPx.left,
+ mDp.cellLayoutBorderSpacePx.x / 2,
mDp.workspacePadding.top + mDp.cellLayoutPaddingPx.top,
mDp.workspacePadding.right + mDp.cellLayoutPaddingPx.right,
mDp.workspacePadding.bottom + mDp.cellLayoutPaddingPx.bottom
@@ -419,7 +378,7 @@
private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
- info.providerName, info.user);
+ info.providerName, info.user, mContext);
if (widgetItem == null) {
return;
}
@@ -546,7 +505,7 @@
// Add first page QSB
if (FeatureFlags.QSB_ON_FIRST_SCREEN && dataModel.isFirstPagePinnedItemEnabled
- && !shouldShowFirstPageWidget()) {
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false);
CellLayoutLayoutParams lp = new CellLayoutLayoutParams(
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 513377a..e90a1e0 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -25,78 +25,53 @@
import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.IconShape;
-import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.UserIconInfo;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
/**
* Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
* that are threadsafe.
*/
public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
- private static final Object sPoolSync = new Object();
- private static LauncherIcons sPool;
- private static int sPoolId = 0;
+ private static final MainThreadInitializedObject<Pool> POOL =
+ new MainThreadInitializedObject<>(Pool::new);
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static LauncherIcons obtain(Context context) {
- if (context instanceof LauncherPreviewRenderer.PreviewContext) {
- return ((LauncherPreviewRenderer.PreviewContext) context).newLauncherIcons(context);
- }
-
- int poolId;
- synchronized (sPoolSync) {
- if (sPool != null) {
- LauncherIcons m = sPool;
- sPool = m.next;
- m.next = null;
- return m;
- }
- poolId = sPoolId;
- }
-
- InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
- return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId);
+ return POOL.get(context).obtain();
}
- public static void clearPool() {
- synchronized (sPoolSync) {
- sPool = null;
- sPoolId++;
- }
+ public static void clearPool(Context context) {
+ POOL.get(context).close();
}
- private final int mPoolId;
-
- private LauncherIcons next;
+ private final ConcurrentLinkedQueue<LauncherIcons> mPool;
private MonochromeIconFactory mMonochromeIconFactory;
- protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
- super(context, fillResIconDpi, iconBitmapSize, IconShape.getShape().enableShapeDetection());
+ protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize,
+ ConcurrentLinkedQueue<LauncherIcons> pool) {
+ super(context, fillResIconDpi, iconBitmapSize,
+ IconShape.INSTANCE.get(context).getShape().enableShapeDetection());
mMonoIconEnabled = Themes.isThemedIconEnabled(context);
- mPoolId = poolId;
+ mPool = pool;
}
/**
* Recycles a LauncherIcons that may be in-use.
*/
public void recycle() {
- synchronized (sPoolSync) {
- if (sPoolId != mPoolId) {
- return;
- }
- // Clear any temporary state variables
- clear();
-
- next = sPool;
- sPool = this;
- }
+ clear();
+ mPool.add(this);
}
@Override
@@ -121,4 +96,33 @@
public void close() {
recycle();
}
+
+ private static class Pool implements SafeCloseable {
+
+ private final Context mContext;
+
+ @NonNull
+ private ConcurrentLinkedQueue<LauncherIcons> mPool = new ConcurrentLinkedQueue<>();
+
+ private Pool(Context context) {
+ mContext = context;
+ }
+
+ public LauncherIcons obtain() {
+ ConcurrentLinkedQueue<LauncherIcons> pool = mPool;
+ LauncherIcons m = pool.poll();
+
+ if (m == null) {
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mContext);
+ return new LauncherIcons(mContext, idp.fillResIconDpi, idp.iconBitmapSize, pool);
+ } else {
+ return m;
+ }
+ }
+
+ @Override
+ public void close() {
+ mPool = new ConcurrentLinkedQueue<>();
+ }
+ }
}
diff --git a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
index 456cde8..480e8f3 100644
--- a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
@@ -246,7 +246,8 @@
protected void setCurrentItem(T item) {
mCurrentItem = item;
- mShift = 0;
+ // Set it to end value directly to skip the animation for outline
+ mShift = Flags.enableFocusOutline() ? 1 : 0;
mTargetItem = null;
}
diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
index 4653bf1..21d157a 100644
--- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
+++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
@@ -19,6 +19,7 @@
import android.graphics.Rect;
import android.view.View;
+import com.android.launcher3.Flags;
import com.android.launcher3.PagedView;
/**
@@ -35,6 +36,28 @@
}
@Override
+ protected boolean shouldDraw(View item) {
+ if (Flags.enableFocusOutline()) {
+ // Not draw outline in page transition because the outline just remains fully
+ // persistent during the transition and does not look smooth
+ return super.shouldDraw(item) && !isInPageTransition(item);
+ } else {
+ return super.shouldDraw(item);
+ }
+ }
+
+ private boolean isInPageTransition(View view) {
+ if (view == null || !(view.getParent() instanceof View)) {
+ return false;
+ }
+ boolean isInTransition = false;
+ if (view instanceof PagedView) {
+ isInTransition = ((PagedView<?>) view).isPageInTransition();
+ }
+ return isInTransition || isInPageTransition((View) view.getParent());
+ }
+
+ @Override
public void viewToRect(View v, Rect outRect) {
// Using FocusedRect here allows views to provide their custom rect for drawing outline,
// e.g. making the Rect bigger than the content to leave some padding between view and
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 441bbb5..25eeacb 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -769,7 +769,19 @@
LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT(1672),
@UiEvent(doc = "Number of preinstalled Private profile apps, shown under separator line")
- LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT(1673)
+ LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT(1673),
+
+ @UiEvent(doc = "Private space lock animation started")
+ LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN(1725),
+
+ @UiEvent(doc = "Private space lock animation finished")
+ LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END(1726),
+
+ @UiEvent(doc = "Private space unlock animation started")
+ LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN(1727),
+
+ @UiEvent(doc = "Private space unlock animation finished")
+ LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END(1728)
// ADD MORE
;
@@ -1205,7 +1217,7 @@
* Creates a new instance of {@link StatsLogManager} based on provided context.
*/
public static StatsLogManager newInstance(Context context) {
- return Overrides.getObject(StatsLogManager.class,
- context.getApplicationContext(), R.string.stats_log_manager_class);
+ return Overrides.getObject(
+ StatsLogManager.class, context, R.string.stats_log_manager_class);
}
}
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index ce563b7..427fb97 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.model;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
@@ -25,9 +26,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel.CallbackTask;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
@@ -49,7 +51,7 @@
/**
* Task to add auto-created workspace items.
*/
-public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
+public class AddWorkspaceItemsTask implements ModelUpdateTask {
private static final String LOG = "AddWorkspaceItemsTask";
@@ -76,15 +78,17 @@
mItemSpaceFinder = itemSpaceFinder;
}
+
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList apps) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
if (mItemList.isEmpty()) {
return;
}
final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
final IntArray addedWorkspaceScreensFinal = new IntArray();
+ final Context context = taskController.getApp().getContext();
synchronized (dataModel) {
IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
@@ -99,7 +103,7 @@
}
// b/139663018 Short-circuit this logic if the icon is a system app
- if (PackageManagerHelper.isSystemApp(app.getContext(),
+ if (PackageManagerHelper.isSystemApp(context,
Objects.requireNonNull(item.getIntent()))) {
continue;
}
@@ -112,7 +116,7 @@
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
if (item instanceof WorkspaceItemFactory) {
- item = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
+ item = ((WorkspaceItemFactory) item).makeWorkspaceItem(context);
}
}
if (item != null) {
@@ -121,13 +125,13 @@
}
InstallSessionHelper packageInstaller =
- InstallSessionHelper.INSTANCE.get(app.getContext());
- LauncherApps launcherApps = app.getContext().getSystemService(LauncherApps.class);
+ InstallSessionHelper.INSTANCE.get(context);
+ LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
for (ItemInfo item : filteredItems) {
// Find appropriate space for the item.
- int[] coords = mItemSpaceFinder.findSpaceForItem(app, dataModel, workspaceScreens,
- addedWorkspaceScreensFinal, item.spanX, item.spanY);
+ int[] coords = mItemSpaceFinder.findSpaceForItem(taskController.getApp(), dataModel,
+ workspaceScreens, addedWorkspaceScreensFinal, item.spanX, item.spanY);
int screenId = coords[0];
ItemInfo itemInfo;
@@ -135,7 +139,7 @@
|| item instanceof LauncherAppWidgetInfo) {
itemInfo = item;
} else if (item instanceof WorkspaceItemFactory) {
- itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
+ itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(context);
} else {
throw new RuntimeException("Unexpected info type");
}
@@ -174,8 +178,8 @@
if (hasActivity) {
// App was installed while launcher was in the background,
// or app was already installed for another user.
- itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user)
- .makeWorkspaceItem(app.getContext());
+ itemInfo = new AppInfo(context, activities.get(0), item.user)
+ .makeWorkspaceItem(context);
if (shortcutExists(dataModel, itemInfo.getIntent(), itemInfo.user)) {
// We need this additional check here since we treat all auto added
@@ -185,16 +189,17 @@
continue;
}
+ IconCache cache = taskController.getApp().getIconCache();
WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
wii.title = "";
- wii.bitmap = app.getIconCache().getDefaultIcon(item.user);
- app.getIconCache().getTitleAndIcon(wii,
+ wii.bitmap = cache.getDefaultIcon(item.user);
+ cache.getTitleAndIcon(wii,
((WorkspaceItemInfo) itemInfo).usingLowResIcon());
}
}
// Add the shortcut to the db
- getModelWriter().addItemToDatabase(itemInfo,
+ taskController.getModelWriter().addItemToDatabase(itemInfo,
LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,
coords[1], coords[2]);
@@ -207,7 +212,7 @@
}
if (!addedItemsFinal.isEmpty()) {
- scheduleCallbackTask(new CallbackTask() {
+ taskController.scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(@NonNull Callbacks callbacks) {
final ArrayList<ItemInfo> addAnimated = new ArrayList<>();
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index a1a05f4..64ebbf3 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -60,7 +60,7 @@
private static final String TAG = "AllAppsList";
private static final Consumer<AppInfo> NO_OP_CONSUMER = a -> { };
-
+ private static final boolean DEBUG = true;
public static final int DEFAULT_APPLICATIONS_NUMBER = 42;
@@ -169,7 +169,7 @@
public AppInfo addPromiseApp(
Context context, PackageInstallInfo installInfo, boolean loadIcon) {
// only if not yet installed
- if (new PackageManagerHelper(context)
+ if (PackageManagerHelper.INSTANCE.get(context)
.isAppInstalled(installInfo.packageName, installInfo.user)) {
return null;
}
@@ -220,6 +220,11 @@
updatedAppInfos.add(appInfo);
} else if (installInfo.state == PackageInstallInfo.STATUS_FAILED
&& !appInfo.isAppStartable()) {
+ if (DEBUG) {
+ Log.w(TAG, "updatePromiseInstallInfo: removing app due to install"
+ + " failure and appInfo not startable."
+ + " package=" + appInfo.getTargetPackage());
+ }
removeApp(i);
}
}
@@ -301,6 +306,7 @@
Context context, String packageName, UserHandle user) {
final ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(context);
final UserCache userCache = UserCache.getInstance(context);
+ final PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
final List<LauncherActivityInfo> matches = context.getSystemService(LauncherApps.class)
.getActivityList(packageName, user);
if (matches.size() > 0) {
@@ -311,7 +317,10 @@
if (user.equals(applicationInfo.user)
&& packageName.equals(applicationInfo.componentName.getPackageName())) {
if (!findActivity(matches, applicationInfo.componentName)) {
- Log.w(TAG, "Changing shortcut target due to app component name change.");
+ if (DEBUG) {
+ Log.w(TAG, "Changing shortcut target due to app component name change."
+ + " package=" + packageName);
+ }
removeApp(i);
}
}
@@ -330,12 +339,16 @@
applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title);
applicationInfo.intent = launchIntent;
AppInfo.updateRuntimeFlagsForActivityTarget(applicationInfo, info,
- userCache.getUserInfo(user), apiWrapper);
+ userCache.getUserInfo(user), apiWrapper, pmHelper);
mDataChanged = true;
}
}
} else {
// Remove all data for this package.
+ if (DEBUG) {
+ Log.w(TAG, "updatePromiseInstallInfo: no Activities matched updated package,"
+ + " removing all apps from package=" + packageName);
+ }
for (int i = data.size() - 1; i >= 0; i--) {
final AppInfo applicationInfo = data.get(i);
if (user.equals(applicationInfo.user)
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 41dbe4e..e6ade61 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -17,8 +17,8 @@
package com.android.launcher3.model;
import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.Flags.enableWorkspaceInflation;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -327,7 +327,7 @@
executeCallbacksTask(c -> {
c.clearPendingBinds();
c.startBinding();
- if (ENABLE_SMARTSPACE_REMOVAL.get()) {
+ if (enableSmartspaceRemovalToggle()) {
c.setIsFirstPagePinnedItemEnabled(
mBgDataModel.isFirstPagePinnedItemEnabled);
}
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
deleted file mode 100644
index 529c30a..0000000
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2016 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.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherModel.CallbackTask;
-import com.android.launcher3.LauncherModel.ModelUpdateTask;
-import com.android.launcher3.celllayout.CellPosMapper;
-import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.BgDataModel.FixedContainerItems;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-/**
- * Extension of {@link ModelUpdateTask} with some utility methods
- */
-public abstract class BaseModelUpdateTask implements ModelUpdateTask {
-
- private static final boolean DEBUG_TASKS = false;
- private static final String TAG = "BaseModelUpdateTask";
-
- // Nullabilities are explicitly omitted here because these are late-init fields,
- // They will be non-null after init(), which is always the case in enqueueModelUpdateTask().
- private LauncherAppState mApp;
- private LauncherModel mModel;
- private BgDataModel mDataModel;
- private AllAppsList mAllAppsList;
- private Executor mUiExecutor;
-
- public void init(@NonNull final LauncherAppState app, @NonNull final LauncherModel model,
- @NonNull final BgDataModel dataModel, @NonNull final AllAppsList allAppsList,
- @NonNull final Executor uiExecutor) {
- mApp = app;
- mModel = model;
- mDataModel = dataModel;
- mAllAppsList = allAppsList;
- mUiExecutor = uiExecutor;
- }
-
- @Override
- public final void run() {
- boolean isModelLoaded = Objects.requireNonNull(mModel).isModelLoaded();
- if (!isModelLoaded) {
- if (DEBUG_TASKS) {
- Log.d(TAG, "Ignoring model task since loader is pending=" + this);
- }
- // Loader has not yet run.
- return;
- }
- execute(mApp, mDataModel, mAllAppsList);
- }
-
- /**
- * Execute the actual task. Called on the worker thread.
- */
- public abstract void execute(@NonNull LauncherAppState app,
- @NonNull BgDataModel dataModel, @NonNull AllAppsList apps);
-
- /**
- * Schedules a {@param task} to be executed on the current callbacks.
- */
- public final void scheduleCallbackTask(@NonNull final CallbackTask task) {
- for (final Callbacks cb : mModel.getCallbacks()) {
- mUiExecutor.execute(() -> task.execute(cb));
- }
- }
-
- public ModelWriter getModelWriter() {
- // Updates from model task, do not deal with icon position in hotseat. Also no need to
- // verify changes as the ModelTasks always push the changes to callbacks
- return mModel.getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null);
- }
-
- public void bindUpdatedWorkspaceItems(@NonNull final List<WorkspaceItemInfo> allUpdates) {
- // Bind workspace items
- List<WorkspaceItemInfo> workspaceUpdates = allUpdates.stream()
- .filter(info -> info.id != ItemInfo.NO_ID)
- .collect(Collectors.toList());
- if (!workspaceUpdates.isEmpty()) {
- scheduleCallbackTask(c -> c.bindWorkspaceItemsChanged(workspaceUpdates));
- }
-
- // Bind extra items if any
- allUpdates.stream()
- .mapToInt(info -> info.container)
- .distinct()
- .mapToObj(mDataModel.extraItems::get)
- .filter(Objects::nonNull)
- .forEach(this::bindExtraContainerItems);
- }
-
- public void bindExtraContainerItems(@NonNull final FixedContainerItems item) {
- scheduleCallbackTask(c -> c.bindExtraContainerItems(item));
- }
-
- public void bindDeepShortcuts(@NonNull final BgDataModel dataModel) {
- final HashMap<ComponentKey, Integer> shortcutMapCopy =
- new HashMap<>(dataModel.deepShortcutMap);
- scheduleCallbackTask(callbacks -> callbacks.bindDeepShortcutMap(shortcutMapCopy));
- }
-
- public void bindUpdatedWidgets(@NonNull final BgDataModel dataModel) {
- final ArrayList<WidgetsListBaseEntry> widgets =
- dataModel.widgetsModel.getWidgetsListForPicker(mApp.getContext());
- scheduleCallbackTask(c -> c.bindAllWidgets(widgets));
- }
-
- public void deleteAndBindComponentsRemoved(final Predicate<ItemInfo> matcher,
- @Nullable final String reason) {
- getModelWriter().deleteItemsFromDatabase(matcher, reason);
-
- // Call the components-removed callback
- scheduleCallbackTask(c -> c.bindWorkspaceComponentsRemoved(matcher));
- }
-
- public void bindApplicationsIfNeeded() {
- if (mAllAppsList.getAndResetChangeFlag()) {
- AppInfo[] apps = mAllAppsList.copyData();
- int flags = mAllAppsList.getFlags();
- Map<PackageUserKey, Integer> packageUserKeytoUidMap = Arrays.stream(apps).collect(
- Collectors.toMap(
- appInfo -> new PackageUserKey(appInfo.componentName.getPackageName(),
- appInfo.user), appInfo -> appInfo.uid, (a, b) -> a));
- scheduleCallbackTask(c -> c.bindAllApplications(apps, flags, packageUserKeytoUidMap));
- }
- }
-}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index d5de4ce..9a9fa5b 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -19,8 +19,8 @@
import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN;
import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED;
import static java.util.stream.Collectors.groupingBy;
@@ -138,7 +138,7 @@
*/
public int lastLoadId = -1;
public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN
- && !ENABLE_SMARTSPACE_REMOVAL.get();
+ && !enableSmartspaceRemovalToggle();
/**
* Clears all the data
@@ -163,7 +163,7 @@
}
}
if ((FeatureFlags.QSB_ON_FIRST_SCREEN
- && !shouldShowFirstPageWidget())
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET)
|| screenSet.isEmpty()) {
screenSet.add(Workspace.FIRST_SCREEN_ID);
}
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 57fefaa..66b4fd9 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -20,7 +20,7 @@
import androidx.annotation.NonNull;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -31,7 +31,7 @@
/**
* Handles changes due to cache updates.
*/
-public class CacheDataUpdatedTask extends BaseModelUpdateTask {
+public class CacheDataUpdatedTask implements ModelUpdateTask {
public static final int OP_CACHE_UPDATE = 1;
public static final int OP_SESSION_UPDATE = 2;
@@ -52,9 +52,9 @@
}
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList apps) {
- IconCache iconCache = app.getIconCache();
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
+ IconCache iconCache = taskController.getApp().getIconCache();
ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
synchronized (dataModel) {
@@ -69,8 +69,8 @@
});
apps.updateIconsAndLabels(mPackages, mUser);
}
- bindUpdatedWorkspaceItems(updatedShortcuts);
- bindApplicationsIfNeeded();
+ taskController.bindUpdatedWorkspaceItems(updatedShortcuts);
+ taskController.bindApplicationsIfNeeded();
}
public boolean isValidShortcut(@NonNull final WorkspaceItemInfo si) {
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 88ca009..132b606 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -16,7 +16,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.content.ContentValues;
@@ -259,7 +259,7 @@
}
case 30: {
if (FeatureFlags.QSB_ON_FIRST_SCREEN
- && !shouldShowFirstPageWidget()) {
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
// Clean up first row in screen 0 as it might contain junk data.
Log.d(TAG, "Cleaning up first row");
db.delete(Favorites.TABLE_NAME,
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index f24a7c1..ad32fc2 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -16,10 +16,10 @@
package com.android.launcher3.model;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
@@ -348,9 +348,9 @@
final Point trg = new Point(trgX, trgY);
final Point next = new Point(0, screenId == 0
&& (FeatureFlags.QSB_ON_FIRST_SCREEN
- && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(destReader.mContext)
+ && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(destReader.mContext)
.getBoolean(SMARTSPACE_ON_HOME_SCREEN, true))
- && !shouldShowFirstPageWidget())
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET)
? 1 /* smartspace */ : 0);
List<DbEntry> existedEntries = destReader.mWorkspaceEntriesByScreenId.get(screenId);
if (existedEntries != null) {
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 90aba2a..551c2d8 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -45,7 +45,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -55,6 +54,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.PersistedItemArray;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.util.HashSet;
@@ -65,7 +65,7 @@
/**
* Class to maintain a queue of pending items to be added to the workspace.
*/
-public class ItemInstallQueue {
+public class ItemInstallQueue implements SafeCloseable {
private static final String LOG = "ItemInstallQueue";
@@ -99,6 +99,9 @@
mContext = context;
}
+ @Override
+ public void close() {}
+
@WorkerThread
private void ensureQueueLoaded() {
Preconditions.assertWorkerThread();
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index b17684c..84130c7 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -17,7 +17,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -57,6 +57,7 @@
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.UserIconInfo;
import java.net.URISyntaxException;
@@ -73,6 +74,7 @@
private final LauncherAppState mApp;
private final Context mContext;
+ private final PackageManagerHelper mPmHelper;
private final IconCache mIconCache;
private final InvariantDeviceProfile mIDP;
private final @Nullable LauncherRestoreEventLogger mRestoreEventLogger;
@@ -114,6 +116,7 @@
public int restoreFlag;
public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState,
+ PackageManagerHelper pmHelper,
@Nullable LauncherRestoreEventLogger restoreEventLogger) {
super(cursor);
@@ -121,6 +124,7 @@
allUsers = userManagerState.allUsers;
mContext = app.getContext();
mIconCache = app.getIconCache();
+ mPmHelper = pmHelper;
mIDP = app.getInvariantDeviceProfile();
mRestoreEventLogger = restoreEventLogger;
@@ -368,7 +372,7 @@
if (mActivityInfo != null) {
AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo, userIconInfo,
- ApiWrapper.INSTANCE.get(mContext));
+ ApiWrapper.INSTANCE.get(mContext), mPmHelper);
}
// from the db
@@ -550,7 +554,8 @@
if (!mOccupied.containsKey(item.screenId)) {
GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
if (item.screenId == Workspace.FIRST_SCREEN_ID && (FeatureFlags.QSB_ON_FIRST_SCREEN
- && !shouldShowFirstPageWidget() && isFirstPagePinnedItemEnabled)) {
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET
+ && isFirstPagePinnedItemEnabled)) {
// Mark the first X columns (X is width of the search container) in the first row as
// occupied (if the feature is enabled) in order to account for the search
// container.
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index a742c75..102d28a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -18,11 +18,11 @@
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
+import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
-import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
@@ -138,6 +138,7 @@
private final LauncherApps mLauncherApps;
private final UserManager mUserManager;
private final UserCache mUserCache;
+ private final PackageManagerHelper mPmHelper;
private final InstallSessionHelper mSessionHelper;
private final IconCache mIconCache;
@@ -170,6 +171,7 @@
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
mUserCache = UserCache.INSTANCE.get(mApp.getContext());
+ mPmHelper = new PackageManagerHelper(mApp.getContext());
mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
mIconCache = mApp.getIconCache();
mUserManagerState = userManagerState;
@@ -320,13 +322,13 @@
verifyNotStopped();
LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext());
- if (SMARTSPACE_AS_A_WIDGET.get() && prefs.get(SHOULD_SHOW_SMARTSPACE)) {
+ if (enableSmartspaceAsAWidget() && prefs.get(SHOULD_SHOW_SMARTSPACE)) {
mLauncherBinder.bindSmartspaceWidget();
// Turn off pref.
prefs.putSync(SHOULD_SHOW_SMARTSPACE.to(false));
logASplit("bindSmartspaceWidget");
verifyNotStopped();
- } else if (!SMARTSPACE_AS_A_WIDGET.get() && WIDGET_ON_FIRST_SCREEN
+ } else if (!enableSmartspaceAsAWidget() && WIDGET_ON_FIRST_SCREEN
&& !prefs.get(LauncherPrefs.SHOULD_SHOW_SMARTSPACE)) {
// Turn on pref.
prefs.putSync(SHOULD_SHOW_SMARTSPACE.to(true));
@@ -397,7 +399,7 @@
logASplit("workspaceDelegateItems");
}
mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN
- && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(
+ && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(
mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true));
}
@@ -407,7 +409,6 @@
@Nullable LoaderMemoryLogger memoryLogger,
@Nullable LauncherRestoreEventLogger restoreEventLogger) {
final Context context = mApp.getContext();
- final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
final boolean isSdCardReady = Utilities.isBootCompleted();
final WidgetInflater widgetInflater = new WidgetInflater(context);
@@ -434,7 +435,8 @@
mShortcutKeyToPinnedShortcuts = new HashMap<>();
final LoaderCursor c = new LoaderCursor(
dbController.query(TABLE_NAME, null, selection, null, null),
- mApp, mUserManagerState, mIsRestoreFromBackup ? restoreEventLogger : null);
+ mApp, mUserManagerState, mPmHelper,
+ mIsRestoreFromBackup ? restoreEventLogger : null);
final Bundle extras = c.getExtras();
mDbName = extras == null ? null : extras.getString(ModelDbController.EXTRA_DB_NAME);
try {
@@ -447,7 +449,7 @@
mUserCache, mUserManagerState, mLauncherApps, mPendingPackages,
mShortcutKeyToPinnedShortcuts, mApp, mBgDataModel,
mWidgetProvidersMap, installingPkgs, isSdCardReady,
- widgetInflater, pmHelper, iconRequestInfos, unlockedUsers,
+ widgetInflater, mPmHelper, iconRequestInfos, unlockedUsers,
allDeepShortcuts);
while (!mStopped && c.moveToNext()) {
@@ -696,7 +698,7 @@
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfo app = apps.get(i);
AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user),
- ApiWrapper.INSTANCE.get(mApp.getContext()), quietMode);
+ ApiWrapper.INSTANCE.get(mApp.getContext()), mPmHelper, quietMode);
if (Flags.enableSupportForArchiving() && app.getApplicationInfo().isArchived) {
// For archived apps, include progress info in case there is a pending
// install session post restart of device.
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 8360b14..2264d35 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -26,6 +26,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.ResourceBasedOverride;
import java.io.FileDescriptor;
@@ -41,15 +42,16 @@
* Creates and initializes a new instance of the delegate
*/
public static ModelDelegate newInstance(
- Context context, LauncherAppState app, AllAppsList appsList, BgDataModel dataModel,
- boolean isPrimaryInstance) {
+ Context context, LauncherAppState app, PackageManagerHelper pmHelper,
+ AllAppsList appsList, BgDataModel dataModel, boolean isPrimaryInstance) {
ModelDelegate delegate = Overrides.getObject(
ModelDelegate.class, context, R.string.model_delegate_class);
- delegate.init(app, appsList, dataModel, isPrimaryInstance);
+ delegate.init(app, pmHelper, appsList, dataModel, isPrimaryInstance);
return delegate;
}
protected final Context mContext;
+ protected PackageManagerHelper mPmHelper;
protected LauncherAppState mApp;
protected AllAppsList mAppsList;
protected BgDataModel mDataModel;
@@ -62,9 +64,10 @@
/**
* Initializes the object with the given params.
*/
- private void init(LauncherAppState app, AllAppsList appsList,
+ private void init(LauncherAppState app, PackageManagerHelper pmHelper, AllAppsList appsList,
BgDataModel dataModel, boolean isPrimaryInstance) {
this.mApp = app;
+ this.mPmHelper = pmHelper;
this.mAppsList = appsList;
this.mDataModel = dataModel;
this.mIsPrimaryInstance = isPrimaryInstance;
diff --git a/src/com/android/launcher3/model/ModelTaskController.kt b/src/com/android/launcher3/model/ModelTaskController.kt
new file mode 100644
index 0000000..266ed0c
--- /dev/null
+++ b/src/com/android/launcher3/model/ModelTaskController.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherModel
+import com.android.launcher3.LauncherModel.CallbackTask
+import com.android.launcher3.celllayout.CellPosMapper
+import com.android.launcher3.model.BgDataModel.FixedContainerItems
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.util.PackageUserKey
+import java.util.Objects
+import java.util.concurrent.Executor
+import java.util.function.Predicate
+
+/** Class with utility methods and properties for running a LauncherModel Task */
+class ModelTaskController(
+ val app: LauncherAppState,
+ val dataModel: BgDataModel,
+ val allAppsList: AllAppsList,
+ private val model: LauncherModel,
+ private val uiExecutor: Executor
+) {
+
+ /** Schedules a {@param task} to be executed on the current callbacks. */
+ fun scheduleCallbackTask(task: CallbackTask) {
+ for (cb in model.callbacks) {
+ uiExecutor.execute { task.execute(cb) }
+ }
+ }
+
+ /**
+ * Updates from model task, do not deal with icon position in hotseat. Also no need to verify
+ * changes as the ModelTasks always push the changes to callbacks
+ */
+ fun getModelWriter() = model.getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null)
+
+ fun bindUpdatedWorkspaceItems(allUpdates: List<WorkspaceItemInfo>) {
+ // Bind workspace items
+ val workspaceUpdates =
+ allUpdates.stream().filter { info -> info.id != ItemInfo.NO_ID }.toList()
+ if (workspaceUpdates.isNotEmpty()) {
+ scheduleCallbackTask { it.bindWorkspaceItemsChanged(workspaceUpdates) }
+ }
+
+ // Bind extra items if any
+ allUpdates
+ .stream()
+ .mapToInt { info: WorkspaceItemInfo -> info.container }
+ .distinct()
+ .mapToObj { dataModel.extraItems.get(it) }
+ .filter { Objects.nonNull(it) }
+ .forEach { bindExtraContainerItems(it) }
+ }
+
+ fun bindExtraContainerItems(item: FixedContainerItems) {
+ scheduleCallbackTask { it.bindExtraContainerItems(item) }
+ }
+
+ fun bindDeepShortcuts(dataModel: BgDataModel) {
+ val shortcutMapCopy = HashMap(dataModel.deepShortcutMap)
+ scheduleCallbackTask { it.bindDeepShortcutMap(shortcutMapCopy) }
+ }
+
+ fun bindUpdatedWidgets(dataModel: BgDataModel) {
+ val widgets = dataModel.widgetsModel.getWidgetsListForPicker(app.context)
+ scheduleCallbackTask { it.bindAllWidgets(widgets) }
+ }
+
+ fun deleteAndBindComponentsRemoved(matcher: Predicate<ItemInfo?>, reason: String?) {
+ getModelWriter().deleteItemsFromDatabase(matcher, reason)
+
+ // Call the components-removed callback
+ scheduleCallbackTask { it.bindWorkspaceComponentsRemoved(matcher) }
+ }
+
+ fun bindApplicationsIfNeeded() {
+ if (allAppsList.getAndResetChangeFlag()) {
+ val apps = allAppsList.copyData()
+ val flags = allAppsList.flags
+ val packageUserKeyToUidMap =
+ apps.associateBy(
+ keySelector = { PackageUserKey(it.componentName!!.packageName, it.user) },
+ valueTransform = { it.uid }
+ )
+ scheduleCallbackTask { it.bindAllApplications(apps, flags, packageUserKeyToUidMap) }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
index b9fba9d..f924a9f 100644
--- a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
@@ -19,7 +19,7 @@
import androidx.annotation.NonNull;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -31,7 +31,7 @@
/**
* Handles updates due to incremental download progress updates.
*/
-public class PackageIncrementalDownloadUpdatedTask extends BaseModelUpdateTask {
+public class PackageIncrementalDownloadUpdatedTask implements ModelUpdateTask {
@NonNull
private final UserHandle mUser;
@@ -49,8 +49,8 @@
}
@Override
- public void execute(@NonNull LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList appsList) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList appsList) {
PackageInstallInfo downloadInfo = new PackageInstallInfo(
mPackageName,
PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING,
@@ -62,11 +62,11 @@
if (!updatedAppInfos.isEmpty()) {
for (AppInfo appInfo : updatedAppInfos) {
appInfo.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
- scheduleCallbackTask(
+ taskController.scheduleCallbackTask(
c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
}
}
- bindApplicationsIfNeeded();
+ taskController.bindApplicationsIfNeeded();
}
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
@@ -79,6 +79,6 @@
}
});
}
- bindUpdatedWorkspaceItems(updatedWorkspaceItems);
+ taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItems);
}
}
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 2457a42..d238213 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -15,12 +15,13 @@
*/
package com.android.launcher3.model;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -33,7 +34,7 @@
/**
* Handles changes due to a sessions updates for a currently installing app.
*/
-public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
+public class PackageInstallStateChangedTask implements ModelUpdateTask {
@NonNull
private final PackageInstallInfo mInstallInfo;
@@ -43,16 +44,17 @@
}
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList apps) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
if (mInstallInfo.state == PackageInstallInfo.STATUS_INSTALLED) {
try {
// For instant apps we do not get package-add. Use setting events to update
// any pinned icons.
- ApplicationInfo ai = app.getContext()
+ Context context = taskController.getApp().getContext();
+ ApplicationInfo ai = context
.getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0);
- if (InstantAppResolver.newInstance(app.getContext()).isInstantApp(ai)) {
- app.getModel().newModelCallbacks()
+ if (InstantAppResolver.newInstance(context).isInstantApp(ai)) {
+ taskController.getApp().getModel().newModelCallbacks()
.onPackageAdded(ai.packageName, mInstallInfo.user);
}
} catch (PackageManager.NameNotFoundException e) {
@@ -66,10 +68,11 @@
List<AppInfo> updatedAppInfos = apps.updatePromiseInstallInfo(mInstallInfo);
if (!updatedAppInfos.isEmpty()) {
for (AppInfo appInfo : updatedAppInfos) {
- scheduleCallbackTask(c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
+ taskController.scheduleCallbackTask(
+ c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
}
}
- bindApplicationsIfNeeded();
+ taskController.bindApplicationsIfNeeded();
}
synchronized (dataModel) {
@@ -90,7 +93,8 @@
}
if (!updates.isEmpty()) {
- scheduleCallbackTask(callbacks -> callbacks.bindRestoreItemsChange(updates));
+ taskController.scheduleCallbackTask(
+ callbacks -> callbacks.bindRestoreItemsChange(updates));
}
}
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 6432d33..29d2269 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -36,9 +36,9 @@
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.FileLog;
@@ -71,11 +71,11 @@
* or when a user availability changes.
*/
@SuppressWarnings("NewApi")
-public class PackageUpdatedTask extends BaseModelUpdateTask {
+public class PackageUpdatedTask implements ModelUpdateTask {
// TODO(b/290090023): Set to false after root causing is done.
- private static final boolean DEBUG = true;
private static final String TAG = "PackageUpdatedTask";
+ private static final boolean DEBUG = true;
public static final int OP_NONE = 0;
public static final int OP_ADD = 1;
@@ -102,8 +102,9 @@
}
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList appsList) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList appsList) {
+ final LauncherAppState app = taskController.getApp();
final Context context = app.getContext();
final IconCache iconCache = app.getIconCache();
@@ -116,29 +117,39 @@
: ItemInfoMatcher.ofPackages(packageSet, mUser);
final HashSet<ComponentName> removedComponents = new HashSet<>();
final HashMap<String, List<LauncherActivityInfo>> activitiesLists = new HashMap<>();
-
+ if (DEBUG) {
+ Log.d(TAG, "Package updated: mOp=" + getOpString()
+ + " packages=" + Arrays.toString(packages));
+ }
switch (mOp) {
case OP_ADD: {
for (int i = 0; i < N; i++) {
- if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
iconCache.updateIconsForPkg(packages[i], mUser);
if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
+ if (DEBUG) {
+ Log.d(TAG, "OP_ADD: PROMISE_APPS_IN_ALL_APPS enabled:"
+ + " removing promise icon apps from package=" + packages[i]);
+ }
appsList.removePackage(packages[i], mUser);
}
- activitiesLists.put(
- packages[i], appsList.addPackage(context, packages[i], mUser));
+ activitiesLists.put(packages[i],
+ appsList.addPackage(context, packages[i], mUser));
}
flagOp = FlagOp.NO_OP.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
break;
}
case OP_UPDATE:
- try (SafeCloseable t =
- appsList.trackRemoves(a -> removedComponents.add(a.componentName))) {
+ try (SafeCloseable t = appsList.trackRemoves(a -> {
+ Log.d(TAG, "OP_UPDATE - AllAppsList.trackRemoves callback:"
+ + " removed component=" + a.componentName
+ + " id=" + a.id
+ + " Look for earlier AllAppsList logs to find more information.");
+ removedComponents.add(a.componentName);
+ })) {
for (int i = 0; i < N; i++) {
- if (DEBUG) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
iconCache.updateIconsForPkg(packages[i], mUser);
- activitiesLists.put(
- packages[i], appsList.updatePackage(context, packages[i], mUser));
+ activitiesLists.put(packages[i],
+ appsList.updatePackage(context, packages[i], mUser));
}
}
// Since package was just updated, the target must be available now.
@@ -146,14 +157,15 @@
break;
case OP_REMOVE: {
for (int i = 0; i < N; i++) {
- FileLog.d(TAG, "Removing app icon: " + packages[i]);
iconCache.removeIconsForPkg(packages[i], mUser);
}
// Fall through
}
case OP_UNAVAILABLE:
for (int i = 0; i < N; i++) {
- if (DEBUG) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
+ if (DEBUG) {
+ Log.d(TAG, getOpString() + ": removing package=" + packages[i]);
+ }
appsList.removePackage(packages[i], mUser);
}
flagOp = FlagOp.NO_OP.addFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
@@ -162,7 +174,6 @@
case OP_UNSUSPEND:
flagOp = FlagOp.NO_OP.setFlag(
WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED, mOp == OP_SUSPEND);
- if (DEBUG) Log.d(TAG, "mAllAppsList.(un)suspend " + N);
appsList.updateDisabledFlags(matcher, flagOp);
break;
case OP_USER_AVAILABILITY_CHANGE: {
@@ -192,7 +203,7 @@
break;
}
- bindApplicationsIfNeeded();
+ taskController.bindApplicationsIfNeeded();
final IntSet removedShortcuts = new IntSet();
// Shortcuts to keep even if the corresponding app was removed
@@ -248,12 +259,21 @@
infoUpdated = true;
} else if (si.hasPromiseIconUi()) {
removedShortcuts.add(si.id);
+ if (DEBUG) {
+ Log.d(TAG, "Removing restored shortcut promise icon"
+ + " that no longer points to valid component."
+ + " id=" + si.id
+ + ", package=" + si.getTargetPackage());
+ }
return;
}
} else if (!isTargetValid) {
removedShortcuts.add(si.id);
- FileLog.e(TAG, "Restored shortcut no longer valid "
- + si.getIntent());
+ FileLog.e(TAG, "Removing shortcut that no longer points to"
+ + " valid component."
+ + " id=" + si.id
+ + " package=" + si.getTargetPackage()
+ + " status=" + si.status);
return;
} else {
si.status = WorkspaceItemInfo.DEFAULT;
@@ -268,6 +288,8 @@
if (isNewApkAvailable) {
List<LauncherActivityInfo> activities = activitiesLists.get(
packageName);
+ // TODO: See if we can migrate this to
+ // AppInfo#updateRuntimeFlagsForActivityTarget
si.setProgressLevel(
activities == null || activities.isEmpty()
? 100
@@ -305,7 +327,7 @@
updatedWorkspaceItems.add(si);
}
if (infoUpdated && si.id != ItemInfo.NO_ID) {
- getModelWriter().updateItemInDatabase(si);
+ taskController.getModelWriter().updateItemInDatabase(si);
}
});
@@ -324,20 +346,21 @@
widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
widgets.add(widgetInfo);
- getModelWriter().updateItemInDatabase(widgetInfo);
+ taskController.getModelWriter().updateItemInDatabase(widgetInfo);
}
}
}
- bindUpdatedWorkspaceItems(updatedWorkspaceItems);
+ taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItems);
if (!removedShortcuts.isEmpty()) {
- deleteAndBindComponentsRemoved(
+ taskController.deleteAndBindComponentsRemoved(
ItemInfoMatcher.ofItemIds(removedShortcuts),
- "removed because the target component is invalid");
+ "removing shortcuts with invalid target components."
+ + " ids=" + removedShortcuts);
}
if (!widgets.isEmpty()) {
- scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
+ taskController.scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
}
}
@@ -345,6 +368,9 @@
if (mOp == OP_REMOVE) {
// Mark all packages in the broadcast to be removed
Collections.addAll(removedPackages, packages);
+ if (DEBUG) {
+ Log.d(TAG, "OP_REMOVE: removing packages=" + Arrays.toString(packages));
+ }
// No need to update the removedComponents as
// removedPackages is a super-set of removedComponents
@@ -353,6 +379,10 @@
final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
for (int i=0; i<N; i++) {
if (!launcherApps.isPackageEnabled(packages[i], mUser)) {
+ if (DEBUG) {
+ Log.d(TAG, "OP_UPDATE:"
+ + " package " + packages[i] + " is disabled, removing package.");
+ }
removedPackages.add(packages[i]);
}
}
@@ -363,7 +393,7 @@
ItemInfoMatcher.ofPackages(removedPackages, mUser)
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
- deleteAndBindComponentsRemoved(removeMatch,
+ taskController.deleteAndBindComponentsRemoved(removeMatch,
"removed because the corresponding package or component is removed. "
+ "mOp=" + mOp + " removedPackages=" + removedPackages.stream().collect(
Collectors.joining(",", "[", "]"))
@@ -382,7 +412,7 @@
for (int i = 0; i < N; i++) {
dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser));
}
- bindUpdatedWidgets(dataModel);
+ taskController.bindUpdatedWidgets(dataModel);
}
}
@@ -398,7 +428,8 @@
return false;
}
// Try to find the best match activity.
- Intent intent = new PackageManagerHelper(context).getAppLaunchIntent(packageName, mUser);
+ Intent intent = PackageManagerHelper.INSTANCE.get(context)
+ .getAppLaunchIntent(packageName, mUser);
if (intent != null) {
si.intent = intent;
si.status = WorkspaceItemInfo.DEFAULT;
@@ -406,4 +437,18 @@
}
return false;
}
+
+ private String getOpString() {
+ return switch (mOp) {
+ case OP_NONE -> "NONE";
+ case OP_ADD -> "ADD";
+ case OP_UPDATE -> "UPDATE";
+ case OP_REMOVE -> "REMOVE";
+ case OP_UNAVAILABLE -> "UNAVAILABLE";
+ case OP_SUSPEND -> "SUSPEND";
+ case OP_UNSUSPEND -> "UNSUSPEND";
+ case OP_USER_AVAILABILITY_CHANGE -> "USER_AVAILABILITY_CHANGE";
+ default -> "UNKNOWN";
+ };
+ }
}
diff --git a/src/com/android/launcher3/model/ReloadStringCacheTask.java b/src/com/android/launcher3/model/ReloadStringCacheTask.java
index 34f7057..3d974d6 100644
--- a/src/com/android/launcher3/model/ReloadStringCacheTask.java
+++ b/src/com/android/launcher3/model/ReloadStringCacheTask.java
@@ -17,13 +17,13 @@
import androidx.annotation.NonNull;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
/**
* Handles updates due to changes in Device Policy Management resources triggered by
* {@link android.app.admin.DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED}.
*/
-public class ReloadStringCacheTask extends BaseModelUpdateTask {
+public class ReloadStringCacheTask implements ModelUpdateTask {
@NonNull
private ModelDelegate mModelDelegate;
@@ -33,12 +33,12 @@
}
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList appsList) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
synchronized (dataModel) {
mModelDelegate.loadStringCache(dataModel.stringCache);
StringCache cloneSC = dataModel.stringCache.clone();
- scheduleCallbackTask(c -> c.bindStringCache(cloneSC));
+ taskController.scheduleCallbackTask(c -> c.bindStringCache(cloneSC));
}
}
}
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index 8cfa3aa..5293316 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -52,7 +52,7 @@
@Override
public void onReceive(Context context, Intent intent) {
final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
- final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
+ final PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
for (PackageUserKey puk : mPackages) {
UserHandle user = puk.mUser;
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 59dd1b1..1916d23 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -22,6 +22,7 @@
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -38,7 +39,7 @@
/**
* Handles changes due to shortcut manager updates (deep shortcut changes)
*/
-public class ShortcutsChangedTask extends BaseModelUpdateTask {
+public class ShortcutsChangedTask implements ModelUpdateTask {
@NonNull
private final String mPackageName;
@@ -61,8 +62,9 @@
}
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList apps) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
+ final LauncherAppState app = taskController.getApp();
final Context context = app.getContext();
// Find WorkspaceItemInfo's that have changed on the workspace.
ArrayList<WorkspaceItemInfo> matchingWorkspaceItems = new ArrayList<>();
@@ -78,8 +80,8 @@
if (!matchingWorkspaceItems.isEmpty()) {
if (mShortcuts.isEmpty()) {
- PackageManagerHelper packageManagerHelper = new PackageManagerHelper(
- app.getContext());
+ PackageManagerHelper packageManagerHelper =
+ PackageManagerHelper.INSTANCE.get(context);
// Verify that the app is indeed installed.
if (!packageManagerHelper.isAppInstalled(mPackageName, mUser)
&& !packageManagerHelper.isAppArchivedForUser(mPackageName, mUser)) {
@@ -115,9 +117,9 @@
});
}
- bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
+ taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
if (!nonPinnedIds.isEmpty()) {
- deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(
+ taskController.deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(
nonPinnedIds.stream()
.map(id -> new ShortcutKey(mPackageName, mUser, id))
.collect(Collectors.toSet())),
@@ -128,7 +130,7 @@
if (mUpdateIdMap) {
// Update the deep shortcut map if the list of ids has changed for an activity.
dataModel.updateDeepShortcutCounts(mPackageName, mUser, mShortcuts);
- bindDeepShortcuts(dataModel);
+ taskController.bindDeepShortcuts(dataModel);
}
}
}
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 63ca35b..3dc5ff3 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -24,6 +24,7 @@
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -40,7 +41,7 @@
/**
* Task to handle changing of lock state of the user
*/
-public class UserLockStateChangedTask extends BaseModelUpdateTask {
+public class UserLockStateChangedTask implements ModelUpdateTask {
@NonNull
private final UserHandle mUser;
@@ -52,8 +53,9 @@
}
@Override
- public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
- @NonNull final AllAppsList apps) {
+ public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
+ @NonNull AllAppsList apps) {
+ LauncherAppState app = taskController.getApp();
Context context = app.getContext();
HashMap<ShortcutKey, ShortcutInfo> pinnedShortcuts = new HashMap<>();
@@ -98,9 +100,10 @@
}
});
}
- bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
+ taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
if (!removedKeys.isEmpty()) {
- deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys),
+ taskController.deleteAndBindComponentsRemoved(
+ ItemInfoMatcher.ofShortcutKeys(removedKeys),
"removed during unlock because it's no longer available"
+ " (possibly due to clear data)");
}
@@ -118,6 +121,6 @@
null, mUser,
new ShortcutRequest(context, mUser).query(ShortcutRequest.ALL));
}
- bindDeepShortcuts(dataModel);
+ taskController.bindDeepShortcuts(dataModel);
}
}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 91ce5ea..5e0edb3 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -118,8 +118,8 @@
Map<PackageUserKey, List<WidgetItem>> packagesToWidgets = new HashMap<>();
mWidgetsList.forEach((packageItemInfo, widgetsAndShortcuts) -> {
List<WidgetItem> widgets = widgetsAndShortcuts.stream()
- .filter(item -> item.widgetInfo != null)
- .collect(toList());
+ .filter(item -> item.widgetInfo != null)
+ .collect(toList());
if (widgets.size() > 0) {
packagesToWidgets.put(
new PackageUserKey(packageItemInfo.packageName, packageItemInfo.user),
@@ -239,20 +239,45 @@
}
}
+ private PackageItemInfo createPackageItemInfo(
+ ComponentName providerName,
+ UserHandle user,
+ int category
+ ) {
+ if (category == NO_CATEGORY) {
+ return new PackageItemInfo(providerName.getPackageName(), user);
+ } else {
+ return new PackageItemInfo("" , category, user);
+ }
+ }
+
+ private IntSet getCategories(ComponentName providerName, Context context) {
+ IntSet categories = WidgetSections.getWidgetsToCategory(context).get(providerName);
+ if (categories != null) {
+ return categories;
+ }
+ categories = new IntSet();
+ categories.add(NO_CATEGORY);
+ return categories;
+ }
+
public WidgetItem getWidgetProviderInfoByProviderName(
- ComponentName providerName, UserHandle user) {
+ ComponentName providerName, UserHandle user, Context context) {
if (!WIDGETS_ENABLED) {
return null;
}
- List<WidgetItem> widgetsList = mWidgetsList.get(
- new PackageItemInfo(providerName.getPackageName(), user));
- if (widgetsList == null) {
- return null;
- }
+ IntSet categories = getCategories(providerName, context);
- for (WidgetItem item : widgetsList) {
- if (item.componentName.equals(providerName)) {
- return item;
+ // Checking if we have a provider in any of the categories.
+ for (Integer category: categories) {
+ PackageItemInfo key = createPackageItemInfo(providerName, user, category);
+ List<WidgetItem> widgets = mWidgetsList.get(key);
+ if (widgets != null) {
+ return widgets.stream().filter(
+ item -> item.componentName.equals(providerName)
+ )
+ .findFirst()
+ .orElse(null);
}
}
return null;
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index cea4380..90e47d6 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -336,7 +336,8 @@
info,
activityInfo,
userCache.getUserInfo(c.user),
- ApiWrapper.INSTANCE[app.context]
+ ApiWrapper.INSTANCE[app.context],
+ pmHelper
)
}
if (
diff --git a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
index 929f698..1a6d178 100644
--- a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
+++ b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
@@ -15,8 +15,8 @@
*/
package com.android.launcher3.model;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import android.util.LongSparseArray;
@@ -68,7 +68,7 @@
// First check the preferred screen.
IntSet screensToExclude = new IntSet();
if (FeatureFlags.QSB_ON_FIRST_SCREEN
- && !shouldShowFirstPageWidget()) {
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
screensToExclude.add(FIRST_SCREEN_ID);
}
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index 18aa6e7..a4281f8 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -90,12 +90,12 @@
*/
public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) {
this(info, UserCache.INSTANCE.get(context).getUserInfo(user),
- ApiWrapper.INSTANCE.get(context),
+ ApiWrapper.INSTANCE.get(context), PackageManagerHelper.INSTANCE.get(context),
context.getSystemService(UserManager.class).isQuietModeEnabled(user));
}
public AppInfo(LauncherActivityInfo info, UserIconInfo userIconInfo,
- ApiWrapper apiWrapper, boolean quietModeEnabled) {
+ ApiWrapper apiWrapper, PackageManagerHelper pmHelper, boolean quietModeEnabled) {
this.componentName = info.getComponentName();
this.container = CONTAINER_ALL_APPS;
this.user = userIconInfo.user;
@@ -105,7 +105,7 @@
runtimeStatusFlags |= FLAG_DISABLED_QUIET_USER;
}
uid = info.getApplicationInfo().uid;
- updateRuntimeFlagsForActivityTarget(this, info, userIconInfo, apiWrapper);
+ updateRuntimeFlagsForActivityTarget(this, info, userIconInfo, apiWrapper, pmHelper);
}
public AppInfo(AppInfo info) {
@@ -184,7 +184,7 @@
*/
public static boolean updateRuntimeFlagsForActivityTarget(
ItemInfoWithIcon info, LauncherActivityInfo lai, UserIconInfo userIconInfo,
- ApiWrapper apiWrapper) {
+ ApiWrapper apiWrapper, PackageManagerHelper pmHelper) {
final int oldProgressLevel = info.getProgressLevel();
final int oldRuntimeStatusFlags = info.runtimeStatusFlags;
ApplicationInfo appInfo = lai.getApplicationInfo();
@@ -216,6 +216,8 @@
PackageManagerHelper.getLoadingProgress(lai),
PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
info.setNonResizeable(apiWrapper.isNonResizeableActivity(lai));
+ info.setSupportsMultiInstance(
+ pmHelper.supportsMultiInstance(lai.getComponentName()));
return (oldProgressLevel != info.getProgressLevel())
|| (oldRuntimeStatusFlags != info.runtimeStatusFlags);
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 8c3efd7..b82d0a0 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -73,6 +73,7 @@
* Represents an item in the launcher.
*/
public class ItemInfo {
+ private static final String TAG = "ItemInfo";
public static final boolean DEBUG = false;
public static final int NO_ID = -1;
@@ -285,7 +286,7 @@
@Override
@NonNull
public final String toString() {
- return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+ return TAG + "(" + dumpProperties() + ")";
}
@NonNull
@@ -427,12 +428,10 @@
@NonNull
protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
- UserIconInfo info = getUserInfo();
- itemBuilder.setIsWork(info != null && info.isWork());
- itemBuilder.setUserType(getUserType(info));
- SettingsCache settingsCache = SettingsCache.INSTANCE.getNoCreate();
- boolean isKidsMode = settingsCache != null && settingsCache.getValue(NAV_BAR_KIDS_MODE, 0);
- itemBuilder.setIsKidsMode(isKidsMode);
+ SettingsCache.INSTANCE.executeIfCreated(cache ->
+ itemBuilder.setIsKidsMode(cache.getValue(NAV_BAR_KIDS_MODE, 0)));
+ UserCache.INSTANCE.executeIfCreated(cache ->
+ itemBuilder.setUserType(getUserType(cache.getUserInfo(user))));
itemBuilder.setRank(rank);
return itemBuilder;
}
@@ -526,15 +525,6 @@
this.title = title;
}
- private UserIconInfo getUserInfo() {
- UserCache userCache = UserCache.INSTANCE.getNoCreate();
- if (userCache == null) {
- return null;
- }
-
- return userCache.getUserInfo(user);
- }
-
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/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index d4c25cb..6ac44ff 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -127,6 +127,11 @@
public static final int FLAG_NOT_RESIZEABLE = 1 << 15;
/**
+ * Flag indicating whether the package related to the item & user supports multiple instances.
+ */
+ public static final int FLAG_SUPPORTS_MULTI_INSTANCE = 1 << 16;
+
+ /**
* Status associated with the system state of the underlying item. This is calculated every
* time a new info is created and not persisted on the disk.
*/
@@ -252,6 +257,24 @@
}
/**
+ * Sets whether this app info supports multi-instance.
+ */
+ protected void setSupportsMultiInstance(boolean supportsMultiInstance) {
+ if (supportsMultiInstance) {
+ runtimeStatusFlags |= FLAG_SUPPORTS_MULTI_INSTANCE;
+ } else {
+ runtimeStatusFlags &= ~FLAG_SUPPORTS_MULTI_INSTANCE;
+ }
+ }
+
+ /**
+ * Returns whether this app info supports multi-instance.
+ */
+ public boolean supportsMultiInstance() {
+ return (runtimeStatusFlags & FLAG_SUPPORTS_MULTI_INSTANCE) != 0;
+ }
+
+ /**
* Sets whether this app info is non-resizeable.
*/
public void setNonResizeable(boolean nonResizeable) {
@@ -301,4 +324,11 @@
drawable.setIsDisabled(isDisabled());
return drawable;
}
+
+ @Override
+ protected String dumpProperties() {
+ return super.dumpProperties()
+ + " supportsMultiInstance=" + supportsMultiInstance()
+ + " nonResizeable=" + isNonResizeable();
+ }
}
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 4a3318e..e66f496 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -32,7 +32,6 @@
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.SessionCommitReceiver;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.util.IntArray;
@@ -41,6 +40,7 @@
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import java.util.ArrayList;
import java.util.HashMap;
@@ -52,7 +52,7 @@
* Utility class to tracking install sessions
*/
@SuppressWarnings("NewApi")
-public class InstallSessionHelper {
+public class InstallSessionHelper implements SafeCloseable {
@NonNull
private static final String LOG = "InstallSessionHelper";
@@ -89,6 +89,9 @@
mLauncherApps = context.getSystemService(LauncherApps.class);
}
+ @Override
+ public void close() { }
+
@WorkerThread
@NonNull
private IntSet getPromiseIconIds() {
@@ -168,7 +171,7 @@
synchronized (mSessionVerifiedMap) {
if (!mSessionVerifiedMap.containsKey(pkg)) {
boolean hasSystemFlag = DEBUG || mAppContext.getPackageName().equals(pkg)
- || new PackageManagerHelper(mAppContext)
+ || PackageManagerHelper.INSTANCE.get(mAppContext)
.getApplicationInfo(pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
mSessionVerifiedMap.put(pkg, hasSystemFlag);
}
@@ -242,7 +245,7 @@
&& sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
&& sessionInfo.getAppIcon() != null
&& !TextUtils.isEmpty(sessionInfo.getAppLabel())
- && !new PackageManagerHelper(mAppContext).isAppInstalled(
+ && !PackageManagerHelper.INSTANCE.get(mAppContext).isAppInstalled(
sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
}
diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java
index 1797c1f..23d3b61 100644
--- a/src/com/android/launcher3/pm/PackageInstallInfo.java
+++ b/src/com/android/launcher3/pm/PackageInstallInfo.java
@@ -22,6 +22,7 @@
import androidx.annotation.NonNull;
public final class PackageInstallInfo {
+ private static final String TAG = "PackageInstallInfo";
public static final int STATUS_INSTALLED = 0;
public static final int STATUS_INSTALLING = 1;
@@ -61,7 +62,7 @@
@Override
public String toString() {
- return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+ return TAG + "(" + dumpProperties() + ")";
}
private String dumpProperties() {
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 185e0b5..b7b557d 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -24,6 +24,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.ArrayMap;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
@@ -81,6 +82,9 @@
@NonNull
private Map<UserHandle, UserIconInfo> mUserToSerialMap;
+ @NonNull
+ private Map<UserHandle, List<String>> mUserToPreInstallAppMap;
+
private UserCache(Context context) {
mContext = context;
mUserToSerialMap = Collections.emptyMap();
@@ -120,6 +124,20 @@
@WorkerThread
private void updateCache() {
mUserToSerialMap = ApiWrapper.INSTANCE.get(mContext).queryAllUsers();
+ mUserToPreInstallAppMap = fetchPreInstallApps();
+ }
+
+ @WorkerThread
+ private Map<UserHandle, List<String>> fetchPreInstallApps() {
+ Map<UserHandle, List<String>> userToPreInstallApp = new ArrayMap<>();
+ mUserToSerialMap.forEach((userHandle, userIconInfo) -> {
+ // Fetch only for private profile, as other profiles have no usages yet.
+ List<String> preInstallApp = userIconInfo.isPrivate()
+ ? ApiWrapper.INSTANCE.get(mContext).getPreInstalledSystemPackages(userHandle)
+ : new ArrayList<>();
+ userToPreInstallApp.put(userHandle, preInstallApp);
+ });
+ return userToPreInstallApp;
}
/**
@@ -172,6 +190,15 @@
}
/**
+ * Returns the pre-installed apps for a user.
+ */
+ @NonNull
+ public List<String> getPreInstallApps(UserHandle user) {
+ List<String> preInstallApp = mUserToPreInstallAppMap.get(user);
+ return preInstallApp == null ? new ArrayList<>() : preInstallApp;
+ }
+
+ /**
* Get a non-themed {@link UserBadgeDrawable} based on the provided {@link UserHandle}.
*/
@Nullable
diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
index 436aa51..575052c 100644
--- a/src/com/android/launcher3/popup/RoundedArrowDrawable.java
+++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
@@ -84,11 +84,12 @@
* @param width of the arrow.
* @param height of the arrow.
* @param radius of the tip of the arrow.
- * @param isPointingLeft or not.
+ * @param isHorizontal or not.
+ * @param isLeftOrTop or not.
* @param color to draw the triangle.
*/
- public RoundedArrowDrawable(float width, float height, float radius, boolean isPointingLeft,
- int color) {
+ private RoundedArrowDrawable(float width, float height, float radius, boolean isHorizontal,
+ boolean isLeftOrTop, int color) {
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(color);
@@ -98,10 +99,47 @@
// Make the drawable with the triangle pointing down...
addDownPointingRoundedTriangleToPath(width, height, radius, mPath);
- // ... then rotate it to the side it needs to point.
- Matrix pathTransform = new Matrix();
- pathTransform.setRotate(isPointingLeft ? 90 : -90, width * 0.5f, height * 0.5f);
- mPath.transform(pathTransform);
+ if (isHorizontal || isLeftOrTop) {
+ // ... then rotate it to the side it needs to point.
+ Matrix pathTransform = new Matrix();
+ int rotationAngle;
+ if (isHorizontal) {
+ rotationAngle = isLeftOrTop ? 90 : -90;
+ } else {
+ // it could only be vertical arrow pointing up
+ rotationAngle = 180;
+ }
+ pathTransform.setRotate(rotationAngle, width * 0.5f, height * 0.5f);
+ mPath.transform(pathTransform);
+ }
+ }
+
+ /**
+ * factory method for an arrow that points to the left or right.
+ *
+ * @param width of the arrow.
+ * @param height of the arrow.
+ * @param radius of the tip of the arrow.
+ * @param isPointingLeft or not.
+ * @param color to draw the triangle.
+ */
+ public static RoundedArrowDrawable createHorizontalRoundedArrow(float width, float height,
+ float radius, boolean isPointingLeft, int color) {
+ return new RoundedArrowDrawable(width, height, radius, true, isPointingLeft, color);
+ }
+
+ /**
+ * factory method for an arrow that points to the left or right.
+ *
+ * @param width of the arrow.
+ * @param height of the arrow.
+ * @param radius of the tip of the arrow.
+ * @param isPointingUp or not.
+ * @param color to draw the triangle.
+ */
+ public static RoundedArrowDrawable createVerticalRoundedArrow(float width, float height,
+ float radius, boolean isPointingUp, int color) {
+ return new RoundedArrowDrawable(width, height, radius, false, isPointingUp, color);
}
@Override
@@ -129,6 +167,14 @@
mPaint.setColorFilter(colorFilter);
}
+ /**
+ * Set shadow layer to internal {@link Paint#setShadowLayer(float, float, float, int) paint}
+ * object
+ */
+ public void setShadowLayer(float shadowBlur, float dx, float dy, int shadowColor) {
+ mPaint.setShadowLayer(shadowBlur, dx, dy, shadowColor);
+ }
+
private static void addDownPointingRoundedTriangleToPath(float width, float height,
float radius, Path path) {
// Calculated for the arrow pointing down, will be flipped later if needed.
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index f56d732..6005573 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -181,8 +181,8 @@
public void onClick(View view) {
dismissTaskMenuView();
Rect sourceBounds = Utilities.getViewBounds(view);
- new PackageManagerHelper(view.getContext()).startDetailsActivityForInfo(
- mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
+ PackageManagerHelper.startDetailsActivityForInfo(view.getContext(), mItemInfo,
+ sourceBounds, ActivityOptions.makeBasic().toBundle());
mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
.log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
}
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index b992a92..3ae643e 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -44,6 +44,7 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.PackageManagerHelper;
/**
* A set of utility methods for Launcher DB used for DB updates and migration.
@@ -107,9 +108,11 @@
Cursor c = db.query(
Favorites.TABLE_NAME, null, "itemType = 1", null, null, null, null);
UserManagerState ums = new UserManagerState();
+ PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
ums.init(UserCache.INSTANCE.get(context),
context.getSystemService(UserManager.class));
- LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, null);
+ LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, pmHelper,
+ null);
IntSet deletedShortcuts = new IntSet();
while (lc.moveToNext()) {
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index d5f1e18..a4ff29f 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -526,10 +526,7 @@
}
logFavoritesTable(controller.getDb(), "launcher db after remap widget ids", null, null);
- LauncherAppState app = LauncherAppState.getInstanceNoCreate();
- if (app != null) {
- app.getModel().forceReload();
- }
+ LauncherAppState.INSTANCE.executeIfCreated(app -> app.getModel().forceReload());
}
private static void logDatabaseWidgetInfo(ModelDbController controller) {
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index f0f376f..8e53aff 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -20,7 +20,7 @@
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_PROVIDER;
-import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import android.app.Activity;
import android.app.Fragment;
@@ -292,7 +292,8 @@
}
public boolean isQsbEnabled() {
- return FeatureFlags.QSB_ON_FIRST_SCREEN && !shouldShowFirstPageWidget();
+ return FeatureFlags.QSB_ON_FIRST_SCREEN
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET;
}
protected Bundle createBindOptions() {
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index 43027da..6d6b3b6 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -26,7 +26,9 @@
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
const val PREINFLATE_ICONS_ROW_COUNT = 4
const val EXTRA_ICONS_COUNT = 2
@@ -52,12 +54,28 @@
return
}
+ // Create a separate context dedicated for all apps preinflation thread. The goal is to
+ // create a separate AssetManager obj internally to avoid lock contention with
+ // AssetManager obj that is associated with the launcher context on the main thread.
+ val allAppsPreInflationContext =
+ ActivityContextDelegate(
+ context.createConfigurationContext(context.resources.configuration),
+ Themes.getActivityThemeRes(context),
+ context
+ )
+
// Because we perform onCreateViewHolder() on worker thread, we need a separate
// adapter/inflator object as they are not thread-safe. Note that the adapter
// just need to perform onCreateViewHolder(parent, VIEW_TYPE_ICON) so it doesn't need
// data source information.
val adapter: RecyclerView.Adapter<BaseAllAppsAdapter.ViewHolder> =
- object : BaseAllAppsAdapter<T>(context, context.appsView.layoutInflater, null, null) {
+ object :
+ BaseAllAppsAdapter<T>(
+ context,
+ context.appsView.layoutInflater.cloneInContext(allAppsPreInflationContext),
+ null,
+ null
+ ) {
override fun setAppsPerRow(appsPerRow: Int) = Unit
override fun getLayoutManager(): RecyclerView.LayoutManager? = null
}
diff --git a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
index 7502a43..2c3035f 100644
--- a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
@@ -135,7 +135,7 @@
hotseatQsbSpace.fixedSize + edgePadding.fixedSize <= maxAvailableSize
private fun logError(message: String) {
- Log.e(LOG_TAG, "${this::class.simpleName}#isValid - $message - $this")
+ Log.e(LOG_TAG, "$LOG_TAG #isValid - $message - $this")
}
companion object {
diff --git a/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
index a4b25e5..ef9b7df 100644
--- a/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
@@ -31,7 +31,7 @@
groupOfSpecs
.onEach { group ->
check(group.widthSpecs.isEmpty() && group.heightSpecs.isNotEmpty()) {
- "${this::class.simpleName} is invalid, only heightSpecs are allowed - " +
+ "$LOG_TAG is invalid, only heightSpecs are allowed - " +
"width list size = ${group.widthSpecs.size}; " +
"height list size = ${group.heightSpecs.size}."
}
@@ -65,6 +65,7 @@
}
companion object {
+ private const val LOG_TAG = "ResponsiveCellSpecsProvider"
@JvmStatic
fun create(resourceHelper: ResourceHelper): ResponsiveCellSpecsProvider {
val parser = ResponsiveSpecsParser(resourceHelper)
@@ -137,11 +138,11 @@
}
private fun logError(message: String) {
- Log.e(LOG_TAG, "${this::class.simpleName}#isValid - $message - $this")
+ Log.e(LOG_TAG, "$LOG_TAG#isValid - $message - $this")
}
companion object {
- private const val LOG_TAG = "CellSpec"
+ const val LOG_TAG = "CellSpec"
}
}
@@ -182,6 +183,7 @@
)
companion object {
+ private const val LOG_TAG = "CalculatedCellSpec"
private fun getCalculatedValue(
availableSpace: Int,
spec: SizeSpec,
@@ -191,10 +193,10 @@
}
override fun toString(): String {
- return "${this::class.simpleName}(" +
+ return "$LOG_TAG(" +
"availableSpace=$availableSpace, iconSize=$iconSize, " +
"iconTextSize=$iconTextSize, iconDrawablePadding=$iconDrawablePadding, " +
- "${spec::class.simpleName}.maxAvailableSize=${spec.maxAvailableSize}" +
+ "${CellSpec.LOG_TAG}.maxAvailableSize=${spec.maxAvailableSize}" +
")"
}
}
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpec.kt b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
index 65e0b32..e69324d 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpec.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
@@ -154,7 +154,7 @@
}
private fun logError(message: String) {
- Log.e(LOG_TAG, "${this::class.simpleName}#isValid - $message - $this")
+ Log.e(LOG_TAG, "$LOG_TAG#isValid - $message - $this")
}
enum class DimensionType {
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt b/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
index 67eaac0..654608d 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
@@ -40,7 +40,7 @@
groupOfSpecs
.onEach { group ->
check(group.widthSpecs.isNotEmpty() && group.heightSpecs.isNotEmpty()) {
- "${this::class.simpleName} is incomplete - " +
+ "$LOG_TAG is incomplete - " +
"width list size = ${group.widthSpecs.size}; " +
"height list size = ${group.heightSpecs.size}."
}
@@ -124,6 +124,7 @@
}
companion object {
+ private const val LOG_TAG = "ResponsiveSpecsProvider"
@JvmStatic
fun create(
resourceHelper: ResourceHelper,
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 51bc339..eea1a7d 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -51,7 +51,7 @@
public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
public static final String TAG = "StateManager";
- // b/279059025
+ // b/279059025, b/325463989
private static final boolean DEBUG = true;
private final AnimationState mConfig = new AnimationState();
@@ -240,16 +240,8 @@
private void goToState(
STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
if (DEBUG) {
- String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
- String truncatedTrace =
- Arrays.stream(stackTrace.split("\\n"))
- .limit(5)
- .skip(1) // Removes the line "java.lang.Exception: tracing state
- // transition"
- .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
- .collect(Collectors.joining("\n"));
Log.d(TAG, "goToState - fromState: " + mState + ", toState: " + state
- + ", partial trace:\n" + truncatedTrace);
+ + ", partial trace:\n" + getTrimmedStackTrace("StateManager.goToState"));
}
animated &= areAnimatorsEnabled();
@@ -336,17 +328,9 @@
public AnimatorSet createAtomicAnimation(
STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) {
if (DEBUG) {
- String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
- String truncatedTrace =
- Arrays.stream(stackTrace.split("\\n"))
- .limit(5)
- .skip(1) // Removes the line "java.lang.Exception: tracing state
- // transition"
- .filter(traceLine -> !traceLine.contains(
- "StateManager.createAtomicAnimation"))
- .collect(Collectors.joining("\n"));
Log.d(TAG, "createAtomicAnimation - fromState: " + fromState + ", toState: " + toState
- + ", partial trace:\n" + truncatedTrace);
+ + ", partial trace:\n" + getTrimmedStackTrace(
+ "StateManager.createAtomicAnimation"));
}
PendingAnimation builder = new PendingAnimation(config.duration);
@@ -481,7 +465,8 @@
*/
public void cancelAnimation() {
if (DEBUG && mConfig.currentAnimation != null) {
- Log.d(TAG, "cancelAnimation - with ongoing animation");
+ Log.d(TAG, "cancelAnimation - with ongoing animation"
+ + ", partial trace:\n" + getTrimmedStackTrace("StateManager.cancelAnimation"));
}
mConfig.reset();
// It could happen that a new animation is set as a result of an endListener on the
@@ -579,6 +564,15 @@
mConfig.playbackController = null;
}
+ private String getTrimmedStackTrace(String callingMethodName) {
+ String stackTrace = Log.getStackTraceString(new Exception());
+ return Arrays.stream(stackTrace.split("\\n"))
+ .skip(2) // Removes the line "java.lang.Exception" and "getTrimmedStackTrace".
+ .filter(traceLine -> !traceLine.contains(callingMethodName))
+ .limit(3)
+ .collect(Collectors.joining("\n"));
+ }
+
private class StartAnimRunnable implements Runnable {
private final AnimatorSet mAnim;
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index d5c9b9f..db2a6e0 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -94,13 +94,10 @@
protected Context mContext;
protected DeviceProfile mDeviceProfile;
- protected LauncherAppState mLauncherAppState;
public void init(Context context) {
mContext = context;
- mDeviceProfile = InvariantDeviceProfile.INSTANCE.
- get(context).getDeviceProfile(context);
- mLauncherAppState = LauncherAppState.getInstanceNoCreate();
+ mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context);
if (sActivityLifecycleCallbacks == null) {
sActivityLifecycleCallbacks = new ActivityLifecycleCallbacksAdapter() {
@Override
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 0ed6ea0..f46dcd3 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -84,7 +84,8 @@
*/
public class ItemClickHandler {
- private static final String TAG = ItemClickHandler.class.getSimpleName();
+ private static final String TAG = "ItemClickHandler";
+ private static final boolean DEBUG = true;
/**
* Instance used for click handling on items
@@ -110,7 +111,19 @@
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
} else if (tag instanceof LauncherAppWidgetInfo) {
if (v instanceof PendingAppWidgetHostView) {
+ if (DEBUG) {
+ String targetPackage = ((LauncherAppWidgetInfo) tag).getTargetPackage();
+ Log.d(TAG, "onClick: PendingAppWidgetHostView clicked for"
+ + " package=" + targetPackage);
+ }
onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
+ } else {
+ if (DEBUG) {
+ String targetPackage = ((LauncherAppWidgetInfo) tag).getTargetPackage();
+ Log.d(TAG, "onClick: LauncherAppWidgetInfo clicked,"
+ + " but not instance of PendingAppWidgetHostView. Returning."
+ + " package=" + targetPackage);
+ }
}
} else if (tag instanceof ItemClickProxy) {
((ItemClickProxy) tag).onItemClicked(v);
@@ -120,6 +133,10 @@
launcher.getString(R.string.long_accessible_way_to_add_shortcut));
Snackbar.show(launcher, msg, null);
} else if (tag instanceof PendingAddWidgetInfo) {
+ if (DEBUG) {
+ String targetPackage = ((PendingAddWidgetInfo) tag).getTargetPackage();
+ Log.d(TAG, "onClick: PendingAddWidgetInfo clicked for package=" + targetPackage);
+ }
CharSequence msg = Utilities.wrapForTts(
launcher.getText(R.string.long_press_widget_to_add),
launcher.getString(R.string.long_accessible_way_to_add));
@@ -199,6 +216,9 @@
LauncherAppWidgetProviderInfo appWidgetInfo = new WidgetManagerHelper(launcher)
.findProvider(info.providerName, info.user);
if (appWidgetInfo == null) {
+ Log.e(TAG, "onClickPendingWidget: Pending widget ready for click setup,"
+ + " but LauncherAppWidgetProviderInfo was null. Returning."
+ + " component=" + info.getTargetComponent());
return;
}
WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo);
@@ -206,6 +226,10 @@
if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
// This should not happen, as we make sure that an Id is allocated during bind.
+ Log.e(TAG, "onClickPendingWidget: Pending widget ready for click setup,"
+ + " and LauncherAppWidgetProviderInfo was found. However,"
+ + " no appWidgetId was allocated. Returning."
+ + " component=" + info.getTargetComponent());
return;
}
addFlowHandler.startBindFlow(launcher, info.appWidgetId, info,
diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java
index 95a0511..b2d0d75 100644
--- a/src/com/android/launcher3/util/ActivityTracker.java
+++ b/src/com/android/launcher3/util/ActivityTracker.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.util;
-import static com.android.launcher3.testing.shared.TestProtocol.GET_FROM_RECENTS_FAILURE;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
-
import android.util.Log;
import androidx.annotation.Nullable;
@@ -46,9 +43,6 @@
public void onActivityDestroyed(T activity) {
if (mCurrentActivity.get() == activity) {
- testLogD(GET_FROM_RECENTS_FAILURE,
- String.format("ActivityTracker.onActivityDestroyed this=%s, activity=%s",
- this, activity));
mCurrentActivity.clear();
}
}
@@ -82,8 +76,6 @@
}
public boolean handleCreate(T activity) {
- testLogD(GET_FROM_RECENTS_FAILURE,
- String.format("ActivityTracker.handleCreate this=%s, activity=%s", this, activity));
mCurrentActivity = new WeakReference<>(activity);
return handleIntent(activity, false /* alreadyOnHome */);
}
diff --git a/src/com/android/launcher3/util/BgObjectWithLooper.java b/src/com/android/launcher3/util/BgObjectWithLooper.java
deleted file mode 100644
index adc3c7d..0000000
--- a/src/com/android/launcher3/util/BgObjectWithLooper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.
- */
-package com.android.launcher3.util;
-
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.annotation.WorkerThread;
-
-import java.util.function.Consumer;
-
-/**
- * Utility class to define an object which does most of it's processing on a
- * dedicated background thread.
- */
-public abstract class BgObjectWithLooper {
-
- /**
- * Start initialization of the object
- */
- public final void initializeInBackground(String threadName) {
- new Thread(this::runOnThread, threadName).start();
- }
-
- private void runOnThread() {
- Looper.prepare();
- onInitialized(Looper.myLooper());
- Looper.loop();
- }
-
- /**
- * Called on the background thread to handle initialization
- */
- @WorkerThread
- protected abstract void onInitialized(Looper looper);
-
- /**
- * Helper method to create a content provider
- */
- protected static ContentObserver newContentObserver(Handler handler, Consumer<Uri> command) {
- return new ContentObserver(handler) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- command.accept(uri);
- }
- };
- }
-}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 8806e27..92fc38f 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -23,6 +23,8 @@
import static com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE;
import static com.android.launcher3.InvariantDeviceProfile.TYPE_TABLET;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
+import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_DESKTOP_MODE_KEY;
+import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_IN_DESKTOP_MODE;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
@@ -88,10 +90,11 @@
public static final int CHANGE_SUPPORTED_BOUNDS = 1 << 3;
public static final int CHANGE_NAVIGATION_MODE = 1 << 4;
public static final int CHANGE_TASKBAR_PINNING = 1 << 5;
+ public static final int CHANGE_DESKTOP_MODE = 1 << 6;
public static final int CHANGE_ALL = CHANGE_ACTIVE_SCREEN | CHANGE_ROTATION
| CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE
- | CHANGE_TASKBAR_PINNING;
+ | CHANGE_TASKBAR_PINNING | CHANGE_DESKTOP_MODE;
private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
private static final String TARGET_OVERLAY_PACKAGE = "android";
@@ -145,16 +148,22 @@
private void attachTaskbarPinningSharedPreferenceChangeListener(Context context) {
mTaskbarPinningPreferenceChangeListener =
(sharedPreferences, key) -> {
- if (TASKBAR_PINNING_KEY.equals(key)
- && mInfo.mIsTaskbarPinned != LauncherPrefs.get(mContext).get(
- TASKBAR_PINNING)
- ) {
+ LauncherPrefs prefs = LauncherPrefs.get(mContext);
+ boolean isTaskbarPinningChanged = TASKBAR_PINNING_KEY.equals(key)
+ && mInfo.mIsTaskbarPinned != prefs.get(TASKBAR_PINNING);
+ boolean isTaskbarPinningDesktopModeChanged =
+ TASKBAR_PINNING_DESKTOP_MODE_KEY.equals(key)
+ && mInfo.mIsTaskbarPinnedInDesktopMode != prefs.get(
+ TASKBAR_PINNING_IN_DESKTOP_MODE);
+ if (isTaskbarPinningChanged || isTaskbarPinningDesktopModeChanged) {
handleInfoChange(mWindowContext.getDisplay());
}
};
LauncherPrefs.get(context).addListener(
mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING);
+ LauncherPrefs.get(context).addListener(
+ mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING_IN_DESKTOP_MODE);
}
/**
@@ -172,6 +181,13 @@
}
/**
+ * Handles info change for desktop mode.
+ */
+ public static void handleInfoChangeForDesktopMode(Context context) {
+ INSTANCE.get(context).handleInfoChange(context.getDisplay());
+ }
+
+ /**
* Enables transient taskbar status for tests.
*/
@VisibleForTesting
@@ -192,6 +208,8 @@
if (enableTaskbarPinning()) {
LauncherPrefs.get(mContext).removeListener(
mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING);
+ LauncherPrefs.get(mContext).removeListener(
+ mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING_IN_DESKTOP_MODE);
}
if (mWindowContext != null) {
mWindowContext.unregisterComponentCallbacks(this);
@@ -309,9 +327,15 @@
FileLog.w(TAG,
"(CHANGE_SUPPORTED_BOUNDS) perDisplayBounds: " + newInfo.mPerDisplayBounds);
}
- if (newInfo.mIsTaskbarPinned != oldInfo.mIsTaskbarPinned) {
+ if ((newInfo.mIsTaskbarPinned != oldInfo.mIsTaskbarPinned)
+ || (newInfo.mIsTaskbarPinnedInDesktopMode
+ != oldInfo.mIsTaskbarPinnedInDesktopMode)) {
change |= CHANGE_TASKBAR_PINNING;
}
+ if (newInfo.mIsInDesktopMode != oldInfo.mIsInDesktopMode) {
+ change |= CHANGE_DESKTOP_MODE;
+ }
+
if (DEBUG) {
Log.d(TAG, "handleInfoChange - change: " + getChangeFlagsString(change));
}
@@ -355,6 +379,9 @@
new ArrayMap<>();
private final boolean mIsTaskbarPinned;
+ private final boolean mIsTaskbarPinnedInDesktopMode;
+
+ private final boolean mIsInDesktopMode;
public Info(Context displayInfoContext) {
/* don't need system overrides for external displays */
@@ -414,6 +441,9 @@
}
mIsTaskbarPinned = LauncherPrefs.get(displayInfoContext).get(TASKBAR_PINNING);
+ mIsTaskbarPinnedInDesktopMode = LauncherPrefs.get(displayInfoContext).get(
+ TASKBAR_PINNING_IN_DESKTOP_MODE);
+ mIsInDesktopMode = wmProxy.isInDesktopMode();
}
/**
@@ -430,10 +460,14 @@
return sTransientTaskbarStatusForTests;
}
if (enableTaskbarPinning()) {
+ if (mIsInDesktopMode) {
+ return !mIsTaskbarPinnedInDesktopMode;
+ }
return !mIsTaskbarPinned;
}
return true;
}
+
/**
* Returns whether the taskbar is pinned in gesture navigation mode.
*/
@@ -441,6 +475,10 @@
return navigationMode == NavigationMode.NO_BUTTON && !isTransientTaskbar();
}
+ public boolean isInDesktopMode() {
+ return mIsInDesktopMode;
+ }
+
/**
* Returns {@code true} if the bounds represent a tablet.
*/
@@ -501,6 +539,7 @@
appendFlag(result, change, CHANGE_SUPPORTED_BOUNDS, "CHANGE_SUPPORTED_BOUNDS");
appendFlag(result, change, CHANGE_NAVIGATION_MODE, "CHANGE_NAVIGATION_MODE");
appendFlag(result, change, CHANGE_TASKBAR_PINNING, "CHANGE_TASKBAR_VARIANT");
+ appendFlag(result, change, CHANGE_DESKTOP_MODE, "CHANGE_DESKTOP_MODE");
return result.toString();
}
@@ -516,6 +555,8 @@
pw.println(" densityDpi=" + info.densityDpi);
pw.println(" navigationMode=" + info.navigationMode.name());
pw.println(" isTaskbarPinned=" + info.mIsTaskbarPinned);
+ pw.println(" isTaskbarPinnedInDesktopMode=" + info.mIsTaskbarPinnedInDesktopMode);
+ pw.println(" isInDesktopMode=" + info.mIsInDesktopMode);
pw.println(" currentSize=" + info.currentSize);
info.mPerDisplayBounds.forEach((key, value) -> pw.println(
" perDisplayBounds - " + key + ": " + value));
diff --git a/src/com/android/launcher3/util/DynamicResource.java b/src/com/android/launcher3/util/DynamicResource.java
index 1008ebb..fbdb5c2 100644
--- a/src/com/android/launcher3/util/DynamicResource.java
+++ b/src/com/android/launcher3/util/DynamicResource.java
@@ -33,7 +33,8 @@
*
* To allow customization for a particular resource, add them to dynamic_resources.xml
*/
-public class DynamicResource implements ResourceProvider, PluginListener<ResourceProvider> {
+public class DynamicResource implements
+ ResourceProvider, PluginListener<ResourceProvider>, SafeCloseable {
private static final MainThreadInitializedObject<DynamicResource> INSTANCE =
new MainThreadInitializedObject<>(DynamicResource::new);
@@ -48,6 +49,11 @@
}
@Override
+ public void close() {
+ PluginManagerWrapper.INSTANCE.get(mContext).removePluginListener(this);
+ }
+
+ @Override
public int getInt(@IntegerRes int resId) {
return mContext.getResources().getInteger(resId);
}
diff --git a/src/com/android/launcher3/util/LockedUserState.kt b/src/com/android/launcher3/util/LockedUserState.kt
index 0a87594..94f9e4f 100644
--- a/src/com/android/launcher3/util/LockedUserState.kt
+++ b/src/com/android/launcher3/util/LockedUserState.kt
@@ -56,12 +56,16 @@
private fun notifyUserUnlocked() {
mUserUnlockedActions.executeAllAndDestroy()
- mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+ Executors.THREAD_POOL_EXECUTOR.execute {
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+ }
}
/** Stops the receiver from listening for ACTION_USER_UNLOCK broadcasts. */
override fun close() {
- mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+ Executors.THREAD_POOL_EXECUTOR.execute {
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
+ }
}
/**
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index b966d8e..1a0f9a0 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -28,17 +28,15 @@
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
/**
* Utility class for defining singletons which are initiated on main thread.
*/
-public class MainThreadInitializedObject<T> {
+public class MainThreadInitializedObject<T extends SafeCloseable> {
private final ObjectProvider<T> mProvider;
private T mValue;
@@ -48,14 +46,14 @@
}
public T get(Context context) {
- if (context instanceof SandboxContext sc) {
+ Context app = context.getApplicationContext();
+ if (app instanceof SandboxApplication sc) {
return sc.getObject(this);
}
if (mValue == null) {
if (Looper.myLooper() == Looper.getMainLooper()) {
- mValue = TraceHelper.allowIpcs("main.thread.object",
- () -> mProvider.get(context.getApplicationContext()));
+ mValue = TraceHelper.allowIpcs("main.thread.object", () -> mProvider.get(app));
} else {
try {
return MAIN_EXECUTOR.submit(() -> get(context)).get();
@@ -67,8 +65,18 @@
return mValue;
}
- public T getNoCreate() {
- return mValue;
+ /**
+ * Executes the callback is the value is already created
+ * @return true if the callback was executed, false otherwise
+ */
+ public boolean executeIfCreated(Consumer<T> callback) {
+ T v = mValue;
+ if (v != null) {
+ callback.accept(v);
+ return true;
+ } else {
+ return false;
+ }
}
@VisibleForTesting
@@ -79,8 +87,8 @@
/**
* Initializes a provider based on resource overrides
*/
- public static <T extends ResourceBasedOverride> MainThreadInitializedObject<T> forOverride(
- Class<T> clazz, int resourceId) {
+ public static <T extends ResourceBasedOverride & SafeCloseable> MainThreadInitializedObject<T>
+ forOverride(Class<T> clazz, int resourceId) {
return new MainThreadInitializedObject<>(c -> Overrides.getObject(clazz, c, resourceId));
}
@@ -89,24 +97,36 @@
T get(Context context);
}
+ public interface SandboxApplication {
+
+ /**
+ * Find a cached object from mObjectMap if we have already created one. If not, generate
+ * an object using the provider.
+ */
+ <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object);
+
+ @UiThread
+ default <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
+ return object.mProvider.get((Context) this);
+ }
+ }
+
/**
* Abstract Context which allows custom implementations for
* {@link MainThreadInitializedObject} providers
*/
- public static class SandboxContext extends ContextWrapper {
+ public static class SandboxContext extends ContextWrapper implements SandboxApplication {
private static final String TAG = "SandboxContext";
- protected final Set<MainThreadInitializedObject> mAllowedObjects;
- protected final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
- protected final ArrayList<Object> mOrderedObjects = new ArrayList<>();
+ private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
+ private final ArrayList<SafeCloseable> mOrderedObjects = new ArrayList<>();
private final Object mDestroyLock = new Object();
private boolean mDestroyed = false;
- public SandboxContext(Context base, MainThreadInitializedObject... allowedObjects) {
+ public SandboxContext(Context base) {
super(base);
- mAllowedObjects = new HashSet<>(Arrays.asList(allowedObjects));
}
@Override
@@ -118,20 +138,14 @@
synchronized (mDestroyLock) {
// Destroy in reverse order
for (int i = mOrderedObjects.size() - 1; i >= 0; i--) {
- Object o = mOrderedObjects.get(i);
- if (o instanceof SafeCloseable) {
- ((SafeCloseable) o).close();
- }
+ mOrderedObjects.get(i).close();
}
mDestroyed = true;
}
}
- /**
- * Find a cached object from mObjectMap if we have already created one. If not, generate
- * an object using the provider.
- */
- protected <T> T getObject(MainThreadInitializedObject<T> object) {
+ @Override
+ public <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object) {
synchronized (mDestroyLock) {
if (mDestroyed) {
Log.e(TAG, "Static object access with a destroyed context");
@@ -142,12 +156,6 @@
}
if (Looper.myLooper() == Looper.getMainLooper()) {
t = createObject(object);
- // Check if we've explicitly allowed the object or if it's a SafeCloseable,
- // it will get destroyed in onDestroy()
- if (!mAllowedObjects.contains(object) && !(t instanceof SafeCloseable)) {
- throw new IllegalStateException("Leaking unknown objects "
- + object + " " + object.mProvider + " " + t);
- }
mObjectMap.put(object, t);
mOrderedObjects.add(t);
return t;
@@ -161,17 +169,12 @@
}
}
- @UiThread
- protected <T> T createObject(MainThreadInitializedObject<T> object) {
- return object.mProvider.get(this);
- }
-
/**
* Put a value into mObjectMap, can be used to put mocked MainThreadInitializedObject
* instances into SandboxContext.
*/
- @VisibleForTesting
- public <T> void putObject(MainThreadInitializedObject<T> object, T value) {
+ public <T extends SafeCloseable> void putObject(
+ MainThreadInitializedObject<T> object, T value) {
mObjectMap.put(object, value);
}
}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.kt b/src/com/android/launcher3/util/OnboardingPrefs.kt
index 370b4c8..ac6e97c 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.kt
+++ b/src/com/android/launcher3/util/OnboardingPrefs.kt
@@ -76,7 +76,5 @@
@JvmField
val HOTSEAT_LONGPRESS_TIP_SEEN = backedUpItem("launcher.hotseat_longpress_tip_seen", false)
- @JvmField
- val TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN =
- backedUpItem("launcher.taskbar_circle_to_search_edu_seen", false)
+ @JvmField val TASKBAR_SEARCH_EDU_SEEN = backedUpItem("launcher.taskbar_search_edu_seen", false)
}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 608bed7..f7c4df4 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -17,6 +17,7 @@
package com.android.launcher3.util;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+import static android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -56,11 +57,15 @@
/**
* Utility methods using package manager
*/
-public class PackageManagerHelper {
+public class PackageManagerHelper implements SafeCloseable{
private static final String TAG = "PackageManagerHelper";
@NonNull
+ public static final MainThreadInitializedObject<PackageManagerHelper> INSTANCE =
+ new MainThreadInitializedObject<>(PackageManagerHelper::new);
+
+ @NonNull
private final Context mContext;
@NonNull
@@ -69,12 +74,19 @@
@NonNull
private final LauncherApps mLauncherApps;
+ private final String[] mLegacyMultiInstanceSupportedApps;
+
public PackageManagerHelper(@NonNull final Context context) {
mContext = context;
mPm = context.getPackageManager();
mLauncherApps = Objects.requireNonNull(context.getSystemService(LauncherApps.class));
+ mLegacyMultiInstanceSupportedApps = mContext.getResources().getStringArray(
+ R.array.config_appsSupportMultiInstancesSplit);
}
+ @Override
+ public void close() { }
+
/**
* Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
* guarantee that the app is on SD card.
@@ -152,11 +164,23 @@
}
}
+ /**
+ * Returns the preferred launch activity intent for a given package.
+ */
@Nullable
public Intent getAppLaunchIntent(@Nullable final String pkg, @NonNull final UserHandle user) {
+ LauncherActivityInfo info = getAppLaunchInfo(pkg, user);
+ return info != null ? AppInfo.makeLaunchIntent(info) : null;
+ }
+
+ /**
+ * Returns the preferred launch activity for a given package.
+ */
+ @Nullable
+ public LauncherActivityInfo getAppLaunchInfo(@Nullable final String pkg,
+ @NonNull final UserHandle user) {
List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(pkg, user);
- return activities.isEmpty() ? null :
- AppInfo.makeLaunchIntent(activities.get(0));
+ return activities.isEmpty() ? null : activities.get(0);
}
/**
@@ -170,10 +194,11 @@
/**
* Starts the details activity for {@code info}
*/
- public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) {
+ public static void startDetailsActivityForInfo(Context context, ItemInfo info,
+ Rect sourceBounds, Bundle opts) {
if (info instanceof ItemInfoWithIcon appInfo
&& (appInfo.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
- mContext.startActivity(ApiWrapper.INSTANCE.get(mContext).getAppMarketActivityIntent(
+ context.startActivity(ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent(
appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()));
return;
}
@@ -189,9 +214,10 @@
}
if (componentName != null) {
try {
- mLauncherApps.startAppDetailsActivity(componentName, info.user, sourceBounds, opts);
+ context.getSystemService(LauncherApps.class).startAppDetailsActivity(componentName,
+ info.user, sourceBounds, opts);
} catch (SecurityException | ActivityNotFoundException e) {
- Toast.makeText(mContext, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch settings", e);
}
}
@@ -276,4 +302,47 @@
return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || (
Flags.enableSupportForArchiving() && info.isArchived);
}
+
+ /**
+ * Returns whether the given component or its application has the multi-instance property set.
+ */
+ public boolean supportsMultiInstance(@NonNull ComponentName component) {
+ // Check the legacy hardcoded allowlist first
+ for (String pkg : mLegacyMultiInstanceSupportedApps) {
+ if (pkg.equals(component.getPackageName())) {
+ return true;
+ }
+ }
+
+ // Check app multi-instance properties after V
+ if (!Utilities.ATLEAST_V) {
+ return false;
+ }
+
+ try {
+ // Check if the component has the multi-instance property
+ return mPm.getProperty(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI, component)
+ .getBoolean();
+ } catch (PackageManager.NameNotFoundException e1) {
+ try {
+ // Check if the application has the multi-instance property
+ return mPm.getProperty(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI,
+ component.getPackageName())
+ .getBoolean();
+ } catch (PackageManager.NameNotFoundException e2) {
+ // Fall through
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether two apps should be considered the same for multi-instance purposes, which
+ * requires additional checks to ensure they can be started as multiple instances.
+ */
+ public static boolean isSameAppForMultiInstance(@NonNull ItemInfo app1,
+ @NonNull ItemInfo app2) {
+ return app1.getTargetPackage().equals(app2.getTargetPackage())
+ && app1.user.equals(app2.user);
+ }
}
diff --git a/src/com/android/launcher3/util/ScreenOnTracker.java b/src/com/android/launcher3/util/ScreenOnTracker.java
index 67530a6..e16e477 100644
--- a/src/com/android/launcher3/util/ScreenOnTracker.java
+++ b/src/com/android/launcher3/util/ScreenOnTracker.java
@@ -27,7 +27,7 @@
/**
* Utility class for tracking if the screen is currently on or off
*/
-public class ScreenOnTracker {
+public class ScreenOnTracker implements SafeCloseable {
public static final MainThreadInitializedObject<ScreenOnTracker> INSTANCE =
new MainThreadInitializedObject<>(ScreenOnTracker::new);
@@ -35,14 +35,21 @@
private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onReceive);
private final CopyOnWriteArrayList<ScreenOnListener> mListeners = new CopyOnWriteArrayList<>();
+ private final Context mContext;
private boolean mIsScreenOn;
private ScreenOnTracker(Context context) {
// Assume that the screen is on to begin with
+ mContext = context;
mIsScreenOn = true;
mReceiver.register(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT);
}
+ @Override
+ public void close() {
+ mReceiver.unregisterReceiverSafely(mContext);
+ }
+
private void onReceive(Intent intent) {
String action = intent.getAction();
if (ACTION_SCREEN_ON.equals(action)) {
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index cd60c1d..51749a7 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -19,14 +19,12 @@
import static android.os.VibrationEffect.createPredefined;
import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.annotation.SuppressLint;
-import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -39,7 +37,7 @@
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
*/
-public class VibratorWrapper {
+public class VibratorWrapper implements SafeCloseable {
public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
new MainThreadInitializedObject<>(VibratorWrapper::new);
@@ -51,6 +49,8 @@
public static final VibrationEffect EFFECT_CLICK =
createPredefined(VibrationEffect.EFFECT_CLICK);
+ private static final Uri HAPTIC_FEEDBACK_URI =
+ Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED);
private static final float LOW_TICK_SCALE = 0.9f;
private static final float DRAG_TEXTURE_SCALE = 0.03f;
@@ -76,6 +76,8 @@
private final Context mContext;
private final Vibrator mVibrator;
private final boolean mHasVibrator;
+ private final SettingsCache.OnChangeListener mHapticChangeListener =
+ isEnabled -> mIsHapticFeedbackEnabled = isEnabled;
private boolean mIsHapticFeedbackEnabled;
@@ -84,16 +86,9 @@
mVibrator = context.getSystemService(Vibrator.class);
mHasVibrator = mVibrator.hasVibrator();
if (mHasVibrator) {
- final ContentResolver resolver = context.getContentResolver();
- mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
- final ContentObserver observer = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
- }
- };
- resolver.registerContentObserver(Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED),
- false /* notifyForDescendants */, observer);
+ SettingsCache cache = SettingsCache.INSTANCE.get(mContext);
+ cache.register(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
+ mIsHapticFeedbackEnabled = cache.getValue(HAPTIC_FEEDBACK_URI, 0);
} else {
mIsHapticFeedbackEnabled = false;
}
@@ -126,6 +121,14 @@
}
}
+ @Override
+ public void close() {
+ if (mHasVibrator) {
+ SettingsCache.INSTANCE.get(mContext)
+ .unregister(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
+ }
+ }
+
/**
* 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
@@ -175,10 +178,6 @@
mLastDragTime = 0;
}
- private boolean isHapticFeedbackEnabled(ContentResolver resolver) {
- return Settings.System.getInt(resolver, HAPTIC_FEEDBACK_ENABLED, 0) == 1;
- }
-
/** Vibrates with the given effect if haptic feedback is available and enabled. */
public void vibrate(VibrationEffect vibrationEffect) {
if (mHasVibrator && mIsHapticFeedbackEnabled) {
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 998191e..0817c0a 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -59,6 +59,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.WindowBounds;
import java.util.ArrayList;
@@ -67,7 +68,7 @@
/**
* Utility class for mocking some window manager behaviours
*/
-public class WindowManagerProxy implements ResourceBasedOverride {
+public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable {
private static final String TAG = "WindowManagerProxy";
public static final int MIN_TABLET_WIDTH = 600;
@@ -114,6 +115,13 @@
}
/**
+ * Returns if we are in desktop mode or not.
+ */
+ public boolean isInDesktopMode() {
+ return false;
+ }
+
+ /**
* Returns the real bounds for the provided display after applying any insets normalization
*/
public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
@@ -305,12 +313,12 @@
navBarHeightPortrait = isTablet
? (mTaskbarDrawnInProcess
- ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+ ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
: getDimenByName(systemRes, NAVBAR_HEIGHT);
navBarHeightLandscape = isTablet
? (mTaskbarDrawnInProcess
- ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+ ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
: (isTabletOrGesture
? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE) : 0);
navbarWidthLandscape = isTabletOrGesture
@@ -474,6 +482,9 @@
NavigationMode.THREE_BUTTONS;
}
+ @Override
+ public void close() { }
+
/**
* @see DisplayCutout#getSafeInsets
*/
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index bf43a22..cfac91a 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -41,6 +41,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
@@ -515,10 +516,21 @@
static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
if (context instanceof ActivityContext) {
return (T) context;
+ } else if (context instanceof ActivityContextDelegate acd) {
+ return (T) acd.mDelegate;
} else if (context instanceof ContextWrapper) {
return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
} else {
return null;
}
}
+
+ class ActivityContextDelegate extends ContextThemeWrapper {
+ public final ActivityContext mDelegate;
+
+ public ActivityContextDelegate(Context base, int themeResId, ActivityContext delegate) {
+ super(base, themeResId);
+ mDelegate = delegate;
+ }
+ }
}
diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java
index 2f0da03..bb4f040 100644
--- a/src/com/android/launcher3/views/ArrowTipView.java
+++ b/src/com/android/launcher3/views/ArrowTipView.java
@@ -54,7 +54,7 @@
*/
public class ArrowTipView extends AbstractFloatingView {
- private static final String TAG = ArrowTipView.class.getSimpleName();
+ private static final String TAG = "ArrowTipView";
private static final long AUTO_CLOSE_TIMEOUT_MILLIS = 10 * 1000;
private static final long SHOW_DELAY_MS = 200;
private static final long SHOW_DURATION_MS = 300;
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
index 5d3fa9b..325c1cd 100644
--- a/src/com/android/launcher3/views/ClipIconView.java
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -18,12 +18,11 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Utilities.boundToRange;
import static com.android.launcher3.Utilities.mapToRange;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static java.lang.Math.max;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
@@ -41,6 +40,7 @@
import android.view.ViewOutlineProvider;
import androidx.annotation.Nullable;
+import androidx.core.util.Consumer;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -75,6 +75,8 @@
private final Rect mOutline = new Rect();
private final Rect mFinalDrawableBounds = new Rect();
+ @Nullable private TaskViewArtist mTaskViewArtist;
+
public ClipIconView(Context context) {
this(context, null);
}
@@ -91,10 +93,28 @@
}
/**
+ * Sets a {@link TaskViewArtist} that will draw a {@link com.android.quickstep.views.TaskView}
+ * within the clip bounds of this view.
+ */
+ public void setTaskViewArtist(TaskViewArtist taskViewArtist) {
+ mTaskViewArtist = taskViewArtist;
+ invalidate();
+ }
+
+ /**
* Update the icon UI to match the provided parameters during an animation frame
*/
public void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
boolean isOpening, View container, DeviceProfile dp) {
+ update(rect, progress, shapeProgressStart, cornerRadius, isOpening, container, dp, 255);
+ }
+
+ /**
+ * Update the icon UI to match the provided parameters during an animation frame, optionally
+ * varying the alpha of the {@link TaskViewArtist}
+ */
+ public void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
+ boolean isOpening, View container, DeviceProfile dp, int taskViewDrawAlpha) {
MarginLayoutParams lp = (MarginLayoutParams) container.getLayoutParams();
float dX = mIsRtl
@@ -108,6 +128,14 @@
float scaleX = rect.width() / minSize;
float scaleY = rect.height() / minSize;
float scale = Math.max(1f, Math.min(scaleX, scaleY));
+ if (mTaskViewArtist != null) {
+ mTaskViewArtist.taskViewDrawWidth = lp.width;
+ mTaskViewArtist.taskViewDrawHeight = lp.height;
+ mTaskViewArtist.taskViewDrawAlpha = taskViewDrawAlpha;
+ mTaskViewArtist.taskViewDrawScale = (mTaskViewArtist.drawForPortraitLayout
+ ? Math.min(lp.height, lp.width) : Math.max(lp.height, lp.width))
+ / mTaskViewArtist.taskViewMinSize;
+ }
if (Float.isNaN(scale) || Float.isInfinite(scale)) {
// Views are no longer laid out, do not update.
@@ -142,14 +170,10 @@
if (mIsAdaptiveIcon) {
if (!isOpening && progress >= shapeProgressStart) {
if (mRevealAnimator == null) {
- mRevealAnimator = (ValueAnimator) IconShape.getShape().createRevealAnimator(
- this, mStartRevealRect, mOutline, mTaskCornerRadius, !isOpening);
- mRevealAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRevealAnimator = null;
- }
- });
+ mRevealAnimator = IconShape.INSTANCE.get(getContext()).getShape()
+ .createRevealAnimator(this, mStartRevealRect,
+ mOutline, mTaskCornerRadius, !isOpening);
+ mRevealAnimator.addListener(forEndCallback(() -> mRevealAnimator = null));
mRevealAnimator.start();
// We pause here so we can set the current fraction ourselves.
mRevealAnimator.pause();
@@ -230,7 +254,8 @@
mStartRevealRect.set(0, 0, originalWidth, originalHeight);
if (!isFolderIcon) {
- Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
+ Utilities.scaleRectAboutCenter(mStartRevealRect,
+ IconShape.INSTANCE.get(getContext()).getNormalizationScale());
}
if (dp.isLandscape) {
@@ -291,6 +316,19 @@
if (mForeground != null) {
mForeground.draw(canvas);
}
+ if (mTaskViewArtist != null) {
+ canvas.saveLayerAlpha(
+ 0,
+ 0,
+ mTaskViewArtist.taskViewDrawWidth,
+ mTaskViewArtist.taskViewDrawHeight,
+ mTaskViewArtist.taskViewDrawAlpha);
+ float drawScale = mTaskViewArtist.taskViewDrawScale;
+ canvas.translate(drawScale * mTaskViewArtist.taskViewTranslationX,
+ drawScale * mTaskViewArtist.taskViewTranslationY);
+ canvas.scale(drawScale, drawScale);
+ mTaskViewArtist.taskViewDrawCallback.accept(canvas);
+ }
canvas.restoreToCount(count);
}
@@ -307,5 +345,37 @@
mRevealAnimator = null;
mTaskCornerRadius = 0;
mOutline.setEmpty();
+ mTaskViewArtist = null;
+ }
+
+ /**
+ * Utility class to help draw a {@link com.android.quickstep.views.TaskView} within
+ * a {@link ClipIconView} bounds.
+ */
+ public static class TaskViewArtist {
+
+ public final Consumer<Canvas> taskViewDrawCallback;
+ public final float taskViewTranslationX;
+ public final float taskViewTranslationY;
+ public final float taskViewMinSize;
+ public final boolean drawForPortraitLayout;
+
+ public int taskViewDrawAlpha;
+ public float taskViewDrawScale;
+ public int taskViewDrawWidth;
+ public int taskViewDrawHeight;
+
+ public TaskViewArtist(
+ Consumer<Canvas> taskViewDrawCallback,
+ float taskViewTranslationX,
+ float taskViewTranslationY,
+ float taskViewMinSize,
+ boolean drawForPortraitLayout) {
+ this.taskViewDrawCallback = taskViewDrawCallback;
+ this.taskViewTranslationX = taskViewTranslationX;
+ this.taskViewTranslationY = taskViewTranslationY;
+ this.taskViewMinSize = taskViewMinSize;
+ this.drawForPortraitLayout = drawForPortraitLayout;
+ }
}
}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index a309e6e..bc66a33 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -77,6 +77,7 @@
canvas.restore();
drawDotIfNecessary(canvas);
+ drawRunningAppIndicatorIfNecessary(canvas);
}
public static class ShadowInfo {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index f560311..1d5a9dc 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -55,7 +55,6 @@
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.popup.SystemShortcut;
@@ -69,7 +68,7 @@
public class FloatingIconView extends FrameLayout implements
Animator.AnimatorListener, OnGlobalLayoutListener, FloatingView {
- private static final String TAG = FloatingIconView.class.getSimpleName();
+ private static final String TAG = "FloatingIconView";
// Manages loading the icon on a worker thread
private static @Nullable IconLoadResult sIconLoadResult;
@@ -146,18 +145,28 @@
}
/**
- * Positions this view to match the size and location of {@param rect}.
- * @param alpha The alpha[0, 1] of the entire floating view.
- * @param progress A value from [0, 1] that represents the animation progress.
- * @param shapeProgressStart The progress value at which to start the shape reveal.
- * @param cornerRadius The corner radius of {@param rect}.
- * @param isOpening True if view is used for app open animation, false for app close animation.
+ * Positions this view to match the size and location of {@code rect}.
*/
public void update(float alpha, RectF rect, float progress, float shapeProgressStart,
float cornerRadius, boolean isOpening) {
- setAlpha(alpha);
+ update(alpha, rect, progress, shapeProgressStart, cornerRadius, isOpening, 0);
+ }
+
+ /**
+ * Positions this view to match the size and location of {@code rect}.
+ * <p>
+ * @param alpha The alpha[0, 1] of the entire floating view.
+ * @param progress A value from [0, 1] that represents the animation progress.
+ * @param shapeProgressStart The progress value at which to start the shape reveal.
+ * @param cornerRadius The corner radius of {@code rect}.
+ * @param isOpening True if view is used for app open animation, false for app close animation.
+ * @param taskViewDrawAlpha the drawn {@link com.android.quickstep.views.TaskView} alpha
+ */
+ public void update(float alpha, RectF rect, float progress, float shapeProgressStart,
+ float cornerRadius, boolean isOpening, int taskViewDrawAlpha) {
+ setAlpha(isLaidOut() ? alpha : 0f);
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening, this,
- mLauncher.getDeviceProfile());
+ mLauncher.getDeviceProfile(), taskViewDrawAlpha);
if (mFadeOutView != null) {
// The alpha goes from 1 to 0 when progress is 0 and 0.33 respectively.
@@ -165,6 +174,14 @@
}
}
+ /**
+ * Sets a {@link com.android.quickstep.views.TaskView} that will draw a
+ * {@link com.android.quickstep.views.TaskView} within the {@code mClipIconView} clip bounds
+ */
+ public void setOverlayArtist(ClipIconView.TaskViewArtist taskViewArtist) {
+ mClipIconView.setTaskViewArtist(taskViewArtist);
+ }
+
@Override
public void onAnimationEnd(Animator animator) {
if (mLoadIconSignal != null) {
@@ -179,8 +196,8 @@
}
/**
- * Sets the size and position of this view to match {@param v}.
- *
+ * Sets the size and position of this view to match {@code v}.
+ * <p>
* @param v The view to copy
* @param positionOut Rect that will hold the size and position of v.
*/
@@ -254,10 +271,11 @@
/**
* Loads the icon and saves the results to {@link #sIconLoadResult}.
+ * <p>
* Runs onIconLoaded callback (if any), which signifies that the FloatingIconView is
* ready to display the icon. Otherwise, the FloatingIconView will grab the results when its
* initialized.
- *
+ * <p>
* @param originalView The View that the FloatingIconView will replace.
* @param info ItemInfo of the originalView
* @param pos The position of the view.
@@ -324,8 +342,8 @@
}
/**
- * Sets the drawables of the {@param originalView} onto this view.
- *
+ * Sets the drawables of the {@code originalView} onto this view.
+ * <p>
* @param drawable The drawable of the original view.
* @param badge The badge of the original view.
* @param iconOffset The amount of offset needed to match this view with the original view.
@@ -368,11 +386,11 @@
/**
* Draws the drawable of the BubbleTextView behind ClipIconView
- *
+ * <p>
* This is used to:
* - Have icon displayed while Adaptive Icon is loading
* - Displays the built in shadow to ensure a clean handoff
- *
+ * <p>
* Allows nullable as this may be cleared when drawing is deferred to ClipIconView.
*/
private void setOriginalDrawableBackground(@Nullable Supplier<Drawable> btvIcon) {
@@ -573,11 +591,12 @@
}
/**
- * Creates a floating icon view for {@param originalView}.
+ * Creates a floating icon view for {@code originalView}.
+ * <p>
* @param originalView The view to copy
* @param visibilitySyncView A view whose visibility should update in sync with originalView.
* @param fadeOutView A view that will fade out as the animation progresses.
- * @param hideOriginal If true, it will hide {@param originalView} while this view is visible.
+ * @param hideOriginal If true, it will hide {@code originalView} while this view is visible.
* Else, we will not draw anything in this view.
* @param positionOut Rect that will hold the size and position of v.
* @param isOpening True if this view replaces the icon for app open animation.
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
deleted file mode 100644
index 53fbd8f..0000000
--- a/src/com/android/launcher3/views/WidgetsEduView.java
+++ /dev/null
@@ -1,141 +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.views;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.R;
-
-/**
- * Education view about widgets.
- */
-public class WidgetsEduView extends AbstractSlideInView<BaseActivity> implements Insettable {
-
- private static final int DEFAULT_CLOSE_DURATION = 200;
-
- private Rect mInsets = new Rect();
-
- public WidgetsEduView(Context context, AttributeSet attr) {
- this(context, attr, 0);
- }
-
- public WidgetsEduView(Context context, AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- protected void handleClose(boolean animate) {
- handleClose(true, DEFAULT_CLOSE_DURATION);
- }
-
- @Override
- protected boolean isOfType(int type) {
- return (type & TYPE_WIDGETS_EDUCATION_DIALOG) != 0;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mContent = findViewById(R.id.edu_view);
- findViewById(R.id.edu_close_button)
- .setOnClickListener(v -> close(/* animate= */ true));
- setContentBackgroundWithParent(mContent.getBackground(), mContent);
- }
-
- @Override
- public void setInsets(Rect insets) {
- mInsets.set(insets);
- mContent.setPadding(mContent.getPaddingStart(),
- mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
- }
-
- @Override
- protected void onUserSwipeToDismissProgressChanged() {
- super.onUserSwipeToDismissProgressChanged();
- setTranslationY(getMeasuredHeight() * (mSwipeToDismissProgress.value / 2));
- }
-
- private void show() {
- attachToContainer();
- animateOpen();
- }
-
- @Override
- protected int getScrimColor(Context context) {
- return context.getResources().getColor(R.color.widgets_picker_scrim);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int width = r - l;
- int height = b - t;
-
- // Lay out the content as center bottom aligned.
- int contentWidth = mContent.getMeasuredWidth();
- int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
- mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
- contentLeft + contentWidth, height);
-
- setTranslationShift(mTranslationShift);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
- int widthUsed;
- if (mInsets.bottom > 0) {
- // Extra space between this view and mContent horizontally when the sheet is shown in
- // portrait mode.
- widthUsed = mInsets.left + mInsets.right;
- } else {
- // Extra space between this view and mContent horizontally when the sheet is shown in
- // landscape mode.
- Rect padding = deviceProfile.workspacePadding;
- widthUsed = Math.max(padding.left + padding.right,
- 2 * (mInsets.left + mInsets.right));
- }
-
- int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
- measureChildWithMargins(mContent, widthMeasureSpec,
- widthUsed, heightMeasureSpec, heightUsed);
- setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
- MeasureSpec.getSize(heightMeasureSpec));
- }
-
- private void animateOpen() {
- if (mIsOpen || mOpenCloseAnimation.getAnimationPlayer().isRunning()) {
- return;
- }
- mIsOpen = true;
- setUpDefaultOpenAnimation().start();
- }
-
- /** Shows widget education dialog. */
- public static WidgetsEduView showEducationDialog(BaseActivity activity) {
- LayoutInflater layoutInflater = LayoutInflater.from(activity);
- WidgetsEduView v = (WidgetsEduView) layoutInflater.inflate(
- R.layout.widgets_edu, activity.getDragLayer(), false);
- v.show();
- return v;
- }
-}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index e5b5daa..1368084 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -17,7 +17,8 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.Flags.enableWidgetTapToAdd;
-import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
import android.content.Context;
@@ -35,17 +36,15 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
-import androidx.core.view.ViewCompat;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -53,7 +52,6 @@
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.AbstractSlideInView;
-import com.android.launcher3.views.ArrowTipView;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -79,6 +77,7 @@
private boolean mDisableNavBarScrim = false;
@Nullable private WidgetCell mWidgetCellWithAddButton = null;
+ @Nullable private WidgetItem mLastSelectedWidgetItem = null;
public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -141,9 +140,17 @@
if (enableWidgetTapToAdd()) {
scrollToWidgetCell(wc);
+
if (mWidgetCellWithAddButton != null) {
- // If there is a add button currently showing, hide it.
- mWidgetCellWithAddButton.hideAddButton(/* animate= */ true);
+ if (mWidgetCellWithAddButton.isShowingAddButton()) {
+ // If there is a add button currently showing, hide it.
+ mWidgetCellWithAddButton.hideAddButton(/* animate= */ true);
+ } else {
+ // The last recorded widget cell to show an add button is no longer showing it,
+ // likely because the widget cell has been recycled or lost focus. If this is
+ // the cell that has been clicked, we will show it below.
+ mWidgetCellWithAddButton = null;
+ }
}
if (mWidgetCellWithAddButton != wc) {
@@ -158,13 +165,26 @@
}
mWidgetCellWithAddButton = mWidgetCellWithAddButton != wc ? wc : null;
+ if (mWidgetCellWithAddButton != null) {
+ mLastSelectedWidgetItem = mWidgetCellWithAddButton.getWidgetItem();
+ } else {
+ mLastSelectedWidgetItem = null;
+ }
} else {
mActivityContext.getItemOnClickListener().onClick(wc);
}
}
+ @Override
+ protected float getShiftRange() {
+ // We add the extra height added during predictive back / swipe up to the shift range, so
+ // that the idle interpolator knows to animate the view off fully.
+ return mContent.getHeight() + getBottomOffsetPx();
+ }
+
/**
- * Click handler for tap to add button.
+ * Click handler for tap to add button. This handler assumes we are in the Launcher activity and
+ * should not be used when the widget sheet is displayed elsewhere.
*/
private void addWidget(@NonNull PendingAddItemInfo info) {
// Using a boolean flag here to make sure the callback is only run once. This should never
@@ -172,19 +192,23 @@
// needed.
final AtomicBoolean hasRun = new AtomicBoolean(false);
addOnCloseListener(() -> {
- if (!hasRun.get()) {
- Launcher.getLauncher(mActivityContext).getAccessibilityDelegate().addToWorkspace(
- info, /*accessibility=*/ false,
+ if (hasRun.get()) return;
+ hasRun.set(true);
+
+ // Going to NORMAL state will also dismiss the All Apps view if it is showing.
+ Launcher launcher = Launcher.getLauncher(mActivityContext);
+ launcher.getStateManager().goToState(NORMAL, forSuccessCallback(() -> {
+ launcher.getAccessibilityDelegate().addToWorkspace(info,
+ /*accessibility=*/ false,
/*finishCallback=*/ (success) -> {
mActivityContext.getStatsLogManager()
.logger()
.withItemInfo(info)
.log(LAUNCHER_WIDGET_ADD_BUTTON_TAP);
});
- hasRun.set(true);
- }
+ }));
});
- handleClose(true);
+ close(/* animate= */ true);
}
/**
@@ -233,6 +257,14 @@
return 0;
}
+ /**
+ * Returns the component of the widget that is currently showing an add button, if any.
+ */
+ @Nullable
+ protected WidgetItem getLastSelectedWidgetItem() {
+ return mLastSelectedWidgetItem;
+ }
+
@Override
public boolean onLongClick(View v) {
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
@@ -358,31 +390,6 @@
return mActivityContext.getSystemUiController();
}
- /** Shows education tip on top center of {@code view} if view is laid out. */
- @Nullable
- protected ArrowTipView showEducationTipOnViewIfPossible(@Nullable View view) {
- if (view == null || !ViewCompat.isLaidOut(view)) {
- return null;
- }
- int[] coords = new int[2];
- view.getLocationOnScreen(coords);
- ArrowTipView arrowTipView =
- new ArrowTipView(mActivityContext, /* isPointingUp= */ false).showAtLocation(
- getContext().getString(R.string.long_press_widget_to_add),
- /* arrowXCoord= */coords[0] + view.getWidth() / 2,
- /* yCoord= */coords[1]);
- if (arrowTipView != null) {
- LauncherPrefs.get(getContext()).put(WIDGETS_EDUCATION_TIP_SEEN, true);
- }
- return arrowTipView;
- }
-
- /** Returns {@code true} if tip has previously been shown on any of {@link BaseWidgetSheet}. */
- protected boolean hasSeenEducationTip() {
- return LauncherPrefs.get(getContext()).get(WIDGETS_EDUCATION_TIP_SEEN)
- || Utilities.isRunningInTestHarness();
- }
-
@Override
protected void setTranslationShift(float translationShift) {
super.setTranslationShift(translationShift);
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index c3e9ad6..44ab966 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -42,7 +42,6 @@
import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
@@ -52,8 +51,7 @@
* {@inheritDoc}
*/
public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
- implements TouchCompleteListener, View.OnLongClickListener,
- LocalColorExtractor.Listener {
+ implements TouchCompleteListener, View.OnLongClickListener {
private static final String TAG = "LauncherAppWidgetHostView";
@@ -70,13 +68,9 @@
private static final String TRACE_METHOD_NAME = "appwidget load-widget ";
- private final Rect mTempRect = new Rect();
private final CheckLongPressHelper mLongPressHelper;
protected final ActivityContext mActivityContext;
- // Maintain the color manager.
- private final LocalColorExtractor mColorExtractor;
-
private boolean mIsScrollable;
private boolean mIsAttachedToWindow;
private boolean mIsAutoAdvanceRegistered;
@@ -84,11 +78,6 @@
private long mDeferUpdatesUntilMillis = 0;
RemoteViews mLastRemoteViews;
- private boolean mHasDeferredColorChange = false;
- private @Nullable SparseIntArray mDeferredColorChange = null;
-
- // The following member variables are only used during drag-n-drop.
- private boolean mIsInDragMode = false;
private boolean mTrackingWidgetUpdate = false;
@@ -109,7 +98,6 @@
if (Themes.getAttrBoolean(context, R.attr.isWorkspaceDarkText)) {
setOnLightBackground(true);
}
- mColorExtractor = new LocalColorExtractor(); // no-op
}
@Override
@@ -177,8 +165,8 @@
}
/**
- * Returns true if the application of {@link RemoteViews} through {@link #updateAppWidget} and
- * colors through {@link #onColorsChanged} are currently being deferred.
+ * Returns true if the application of {@link RemoteViews} through {@link #updateAppWidget} are
+ * currently being deferred.
* @see #beginDeferringUpdates()
*/
private boolean isDeferringUpdates() {
@@ -187,9 +175,8 @@
/**
* Begin deferring the application of any {@link RemoteViews} updates made through
- * {@link #updateAppWidget} and color changes through {@link #onColorsChanged} until
- * {@link #endDeferringUpdates()} has been called or the next {@link #updateAppWidget} or
- * {@link #onColorsChanged} call after {@link #UPDATE_LOCK_TIMEOUT_MILLIS} have elapsed.
+ * {@link #updateAppWidget} until {@link #endDeferringUpdates()} has been called or the next
+ * {@link #updateAppWidget} call after {@link #UPDATE_LOCK_TIMEOUT_MILLIS} have elapsed.
*/
public void beginDeferringUpdates() {
mDeferUpdatesUntilMillis = SystemClock.uptimeMillis() + UPDATE_LOCK_TIMEOUT_MILLIS;
@@ -197,26 +184,16 @@
/**
* Stop deferring the application of {@link RemoteViews} updates made through
- * {@link #updateAppWidget} and color changes made through {@link #onColorsChanged} and apply
- * any deferred updates.
+ * {@link #updateAppWidget} and apply any deferred updates.
*/
public void endDeferringUpdates() {
RemoteViews remoteViews;
- SparseIntArray deferredColors;
- boolean hasDeferredColors;
mDeferUpdatesUntilMillis = 0;
remoteViews = mLastRemoteViews;
- deferredColors = mDeferredColorChange;
- hasDeferredColors = mHasDeferredColorChange;
- mDeferredColorChange = null;
- mHasDeferredColorChange = false;
if (remoteViews != null) {
updateAppWidget(remoteViews);
}
- if (hasDeferredColors) {
- onColorsChanged(deferredColors);
- }
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -242,7 +219,6 @@
super.onAttachedToWindow();
mIsAttachedToWindow = true;
checkIfAutoAdvance();
- mColorExtractor.setListener(this);
}
@Override
@@ -253,7 +229,6 @@
// state is updated. So isAttachedToWindow() will return true until next frame.
mIsAttachedToWindow = false;
checkIfAutoAdvance();
- mColorExtractor.setListener(null);
}
@Override
@@ -292,29 +267,6 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mIsScrollable = checkScrollableRecursively(this);
-
- if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo info) {
- mTempRect.set(left, top, right, bottom);
- mColorExtractor.setWorkspaceLocation(mTempRect, (View) getParent(), info.screenId);
- }
- }
-
- /** Starts the drag mode. */
- public void startDrag() {
- mIsInDragMode = true;
- }
-
- /** Handles a drag event occurred on a workspace page corresponding to the {@code screenId}. */
- public void handleDrag(Rect rectInView, View view, int screenId) {
- if (mIsInDragMode) {
- mColorExtractor.setWorkspaceLocation(rectInView, view, screenId);
- }
- }
-
- /** Ends the drag mode. */
- public void endDrag() {
- mIsInDragMode = false;
- requestLayout();
}
/**
@@ -338,20 +290,6 @@
}
@Override
- public void onColorsChanged(SparseIntArray colors) {
- if (isDeferringUpdates()) {
- mDeferredColorChange = colors;
- mHasDeferredColorChange = true;
- return;
- }
- mDeferredColorChange = null;
- mHasDeferredColorChange = false;
-
- // setColorResources will reapply the view, which must happen in the UI thread.
- post(() -> setColorResources(colors));
- }
-
- @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(getClass().getName());
diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java
index 96e7531..7b500c7 100644
--- a/src/com/android/launcher3/widget/LocalColorExtractor.java
+++ b/src/com/android/launcher3/widget/LocalColorExtractor.java
@@ -17,11 +17,8 @@
package com.android.launcher3.widget;
import android.app.WallpaperColors;
-import android.appwidget.AppWidgetHostView;
import android.content.Context;
-import android.graphics.Rect;
import android.util.SparseIntArray;
-import android.view.View;
import androidx.annotation.Nullable;
@@ -31,18 +28,6 @@
/** Extracts the colors we need from the wallpaper at given locations. */
public class LocalColorExtractor implements ResourceBasedOverride {
- /** Listener for color changes on a screen location. */
- public interface Listener {
- /**
- * Method called when the colors on a registered location has changed.
- *
- * {@code extractedColors} maps the color resources {@code android.R.colors.system_*} to
- * their value, in a format that can be passed directly to
- * {@link AppWidgetHostView#setColorResources(SparseIntArray)}.
- */
- void onColorsChanged(SparseIntArray extractedColors);
- }
-
/**
* Creates a new instance of LocalColorExtractor
*/
@@ -51,19 +36,6 @@
R.string.local_colors_extraction_class);
}
- /** Sets the object that will receive the color changes. */
- public void setListener(@Nullable Listener listener) {
- // no-op
- }
-
- /**
- * Sets the location used for color extraction
- * @param pos position to use for color extraction
- * @param child view whose coordinate space is used for {@code pos}
- * @param screenId the workspace screenId
- */
- public void setWorkspaceLocation(Rect pos, View child, int screenId) { }
-
/**
* Updates the base context to contain the colors override
*/
@@ -76,5 +48,4 @@
public SparseIntArray generateColorsOverride(WallpaperColors colors) {
return null;
}
-
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index faad307..8857774 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -44,7 +44,6 @@
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.RoundDrawableWrapper;
-import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
/**
* Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
@@ -132,8 +131,6 @@
}
if (mAppWidgetHostViewPreview != null) {
previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
- launcher.getDragController()
- .addDragListener(new AppWidgetHostViewDragListener(launcher));
}
if (preview == null && mAppWidgetHostViewPreview == null) {
Drawable p = new FastBitmapDrawable(new DatabaseWidgetPreviewLoader(launcher)
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index ab007fb..eac2ce7 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -23,8 +23,13 @@
import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
import static com.android.launcher3.widget.util.WidgetSizes.getWidgetItemSizePx;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -45,11 +50,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedPropertySetter;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.RoundDrawableWrapper;
import com.android.launcher3.model.WidgetItem;
@@ -77,7 +84,7 @@
private static final boolean DEBUG = false;
private static final int FADE_IN_DURATION_MS = 90;
- private static final int ADD_BUTTON_FADE_DURATION_MS = 300;
+ private static final int ADD_BUTTON_FADE_DURATION_MS = 100;
/**
* The requested scale of the preview container. It can be lower than this as well.
@@ -110,6 +117,7 @@
private int mSourceContainer = CONTAINER_WIDGETS_TRAY;
private CancellableTask mIconLoadRequest;
+ private boolean mIsShowingAddButton = false;
public WidgetCell(Context context) {
this(context, null);
@@ -495,6 +503,15 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+
+ if (changed && isShowingAddButton()) {
+ post(this::setupIconOrTextButton);
+ }
+ }
+
/**
* Loads a high resolution package icon to show next to the widget title.
*/
@@ -534,30 +551,57 @@
* @param callback Callback to be set on the button.
*/
public void showAddButton(View.OnClickListener callback) {
- mWidgetAddButton.setAlpha(0F);
- mWidgetAddButton.setVisibility(VISIBLE);
- mWidgetAddButton.setOnClickListener(callback);
- mWidgetAddButton.animate().cancel();
- mWidgetAddButton.animate()
- .alpha(1F)
- .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+ if (mIsShowingAddButton) return;
+ mIsShowingAddButton = true;
- mWidgetTextContainer.animate().cancel();
- mWidgetTextContainer.animate()
- .alpha(0F)
- .setDuration(ADD_BUTTON_FADE_DURATION_MS)
- .withEndAction(() -> {
- mWidgetTextContainer.setVisibility(INVISIBLE);
- });
+ setupIconOrTextButton();
+ mWidgetAddButton.setOnClickListener(callback);
+ fadeThrough(/* hide= */ mWidgetTextContainer, /* show= */ mWidgetAddButton,
+ ADD_BUTTON_FADE_DURATION_MS, Interpolators.LINEAR);
+ }
+
+ /**
+ * Depending on the width of the cell, set up the add button to be icon-only or icon+text.
+ */
+ private void setupIconOrTextButton() {
+ String addText = getResources().getString(R.string.widget_add_button_label);
+ Rect textSize = new Rect();
+ mWidgetAddButton.getPaint().getTextBounds(addText, 0, addText.length(), textSize);
+ int startPadding = getResources()
+ .getDimensionPixelSize(R.dimen.widget_cell_add_button_start_padding);
+ int endPadding = getResources()
+ .getDimensionPixelSize(R.dimen.widget_cell_add_button_end_padding);
+ int drawableWidth = getResources()
+ .getDimensionPixelSize(R.dimen.widget_cell_add_button_drawable_width);
+ int drawablePadding = getResources()
+ .getDimensionPixelSize(R.dimen.widget_cell_add_button_drawable_padding);
+ int textButtonWidth = textSize.width() + startPadding + endPadding + drawableWidth
+ + drawablePadding;
+ if (textButtonWidth > getMeasuredWidth()) {
+ // Setup icon-only button
+ mWidgetAddButton.setText(null);
+ int startIconPadding = getResources()
+ .getDimensionPixelSize(R.dimen.widget_cell_add_icon_button_start_padding);
+ mWidgetAddButton.setPaddingRelative(/* start= */ startIconPadding, /* top= */ 0,
+ /* end= */ endPadding, /* bottom= */ 0);
+ mWidgetAddButton.setCompoundDrawablePadding(0);
+ } else {
+ // Setup icon + text button
+ mWidgetAddButton.setText(addText);
+ mWidgetAddButton.setPaddingRelative(/* start= */ startPadding, /* top= */ 0,
+ /* end= */ endPadding, /* bottom= */ 0);
+ mWidgetAddButton.setCompoundDrawablePadding(drawablePadding);
+ }
}
/**
* Hide tap to add button.
*/
public void hideAddButton(boolean animate) {
+ if (!mIsShowingAddButton) return;
+ mIsShowingAddButton = false;
+
mWidgetAddButton.setOnClickListener(null);
- mWidgetAddButton.animate().cancel();
- mWidgetTextContainer.animate().cancel();
if (!animate) {
mWidgetAddButton.setVisibility(INVISIBLE);
@@ -566,17 +610,45 @@
return;
}
- mWidgetAddButton.animate()
- .alpha(0F)
- .setDuration(ADD_BUTTON_FADE_DURATION_MS)
- .withEndAction(() -> {
- mWidgetAddButton.setVisibility(INVISIBLE);
- });
+ fadeThrough(/* hide= */ mWidgetAddButton, /* show= */ mWidgetTextContainer,
+ ADD_BUTTON_FADE_DURATION_MS, Interpolators.LINEAR);
+ }
- mWidgetTextContainer.setAlpha(0F);
- mWidgetTextContainer.setVisibility(VISIBLE);
- mWidgetTextContainer.animate()
- .alpha(1F)
- .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+ public boolean isShowingAddButton() {
+ return mIsShowingAddButton;
+ }
+
+ private static void fadeThrough(View hide, View show, int durationMs,
+ TimeInterpolator interpolator) {
+ AnimatedPropertySetter setter = new AnimatedPropertySetter();
+
+ Animator hideAnim = setter.setViewAlpha(hide, 0F, interpolator).setDuration(durationMs);
+ if (hideAnim instanceof ObjectAnimator anim) {
+ anim.setAutoCancel(true);
+ }
+
+ Animator showAnim = setter.setViewAlpha(show, 1F, interpolator).setDuration(durationMs);
+ if (showAnim instanceof ObjectAnimator anim) {
+ anim.setAutoCancel(true);
+ }
+
+ AnimatorSet set = new AnimatorSet();
+ set.playSequentially(hideAnim, showAnim);
+ set.start();
+ }
+
+ /**
+ * Returns true if this WidgetCell is displaying the same item as info.
+ */
+ public boolean matchesItem(WidgetItem info) {
+ if (info == null || mItem == null) return false;
+ if (info.widgetInfo != null && mItem.widgetInfo != null) {
+ return info.widgetInfo.getUser().equals(mItem.widgetInfo.getUser())
+ && info.widgetInfo.getComponent().equals(mItem.widgetInfo.getComponent());
+ } else if (info.activityInfo != null && mItem.activityInfo != null) {
+ return info.activityInfo.getUser().equals(mItem.activityInfo.getUser())
+ && info.activityInfo.getComponent().equals(mItem.activityInfo.getComponent());
+ }
+ return false;
}
}
diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java
index d293d15..9132b4f 100644
--- a/src/com/android/launcher3/widget/WidgetManagerHelper.java
+++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java
@@ -26,6 +26,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.Log;
import android.widget.RemoteViews;
import androidx.annotation.NonNull;
@@ -104,6 +105,8 @@
// If exception is thrown because of device is locked, it means a race condition occurs
// that the user got locked again while launcher is processing the event. In this case
// we should return empty list.
+ Log.e(TAG, "getAllProviders: Error getting installed providers for"
+ + " package=" + packageUser.mPackageName, e);
return Collections.emptyList();
}
}
@@ -133,6 +136,8 @@
return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
}
}
+ Log.w(TAG, "findProvider: No App Widget Provider found for component=" + provider
+ + " user=" + user);
return null;
}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 97aa67d..4ea2426 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.IntProperty;
import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -50,57 +49,11 @@
* Bottom sheet for the "Widgets" system shortcut in the long-press popup.
*/
public class WidgetsBottomSheet extends BaseWidgetSheet {
- private static final String TAG = "WidgetsBottomSheet";
-
- private static final IntProperty<View> PADDING_BOTTOM =
- new IntProperty<View>("paddingBottom") {
- @Override
- public void setValue(View view, int paddingBottom) {
- view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
- view.getPaddingRight(), paddingBottom);
- }
-
- @Override
- public Integer get(View view) {
- return view.getPaddingBottom();
- }
- };
-
private static final int DEFAULT_CLOSE_DURATION = 200;
- private static final long EDUCATION_TIP_DELAY_MS = 300;
private ItemInfo mOriginalItemInfo;
@Px private int mMaxHorizontalSpan;
- private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
- new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (hasSeenEducationTip()) {
- removeOnLayoutChangeListener(this);
- return;
- }
- // Widgets are loaded asynchronously, We are adding a delay because we only want
- // to show the tip when the widget preview has finished loading and rendering in
- // this view.
- removeCallbacks(mShowEducationTipTask);
- postDelayed(mShowEducationTipTask, EDUCATION_TIP_DELAY_MS);
- }
- };
-
- private final Runnable mShowEducationTipTask = () -> {
- if (hasSeenEducationTip()) {
- removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
- return;
- }
- View viewForTip = ((ViewGroup) ((TableLayout) findViewById(R.id.widgets_table))
- .getChildAt(0)).getChildAt(0);
- if (showEducationTipOnViewIfPossible(viewForTip) != null) {
- removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
- }
- };
-
public WidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -108,9 +61,6 @@
public WidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
- if (!hasSeenEducationTip()) {
- addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
- }
}
@Override
@@ -119,9 +69,6 @@
mContent = findViewById(R.id.widgets_bottom_sheet);
setContentBackgroundWithParent(
getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet), mContent);
- View scrollView = findViewById(R.id.widgets_table_scroll_view);
- scrollView.setOutlineProvider(mViewOutlineProvider);
- scrollView.setClipToOutline(true);
}
@Override
@@ -195,6 +142,9 @@
row.forEach(widgetItem -> {
WidgetCell widget = addItemCell(tableRow);
widget.applyFromCellItem(widgetItem);
+ if (widget.matchesItem(getLastSelectedWidgetItem())) {
+ widget.callOnClick();
+ }
});
widgetsTable.addView(tableRow);
});
@@ -216,6 +166,7 @@
protected WidgetCell addItemCell(ViewGroup parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
.inflate(R.layout.widget_cell, parent, false);
+ widget.setOnClickListener(this);
View previewContainer = widget.findViewById(R.id.widget_preview_container);
previewContainer.setOnClickListener(this);
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index 05fe8e3..50012b3 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -16,7 +16,7 @@
package com.android.launcher3.widget.custom;
-import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
+import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
import static com.android.launcher3.model.data.LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
@@ -70,7 +70,7 @@
PluginManagerWrapper.INSTANCE.get(context)
.addPluginListener(this, CustomWidgetPlugin.class, true);
- if (SMARTSPACE_AS_A_WIDGET.get()) {
+ if (enableSmartspaceAsAWidget()) {
for (String s: context.getResources()
.getStringArray(R.array.custom_widget_providers)) {
try {
diff --git a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java b/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java
deleted file mode 100644
index 3e54b33..0000000
--- a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.dragndrop;
-
-import com.android.launcher3.DropTarget;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
-
-/** A drag listener of {@link LauncherAppWidgetHostView}. */
-public final class AppWidgetHostViewDragListener implements DragController.DragListener {
- private final Launcher mLauncher;
- private LauncherAppWidgetHostView mAppWidgetHostView;
-
- public AppWidgetHostViewDragListener(Launcher launcher) {
- mLauncher = launcher;
- }
-
- @Override
- public void onDragStart(DropTarget.DragObject dragObject, DragOptions unused) {
- if (dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView) {
- mAppWidgetHostView = (LauncherAppWidgetHostView) dragObject.dragView.getContentView();
- mAppWidgetHostView.startDrag();
- } else {
- mLauncher.getDragController().removeDragListener(this);
- }
- }
-
- @Override
- public void onDragEnd() {
- mAppWidgetHostView.endDrag();
- mLauncher.getDragController().removeDragListener(this);
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
index c3906a6..80bda22 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
@@ -62,16 +62,17 @@
// via the overridden WidgetRecommendationCategoryProvider resource.
Preconditions.assertWorkerThread();
- PackageManagerHelper pmHelper = new PackageManagerHelper(context);
- if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
- String widgetComponentName = item.widgetInfo.getComponent().getClassName();
- ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
- item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
- 0 /* flags */);
- if (applicationInfo != null) {
- int predictionCategory = applicationInfo.category;
- return getCategoryFromApplicationCategory(context, predictionCategory,
- widgetComponentName);
+ try (PackageManagerHelper pmHelper = new PackageManagerHelper(context)) {
+ if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
+ String widgetComponentName = item.widgetInfo.getComponent().getClassName();
+ ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
+ item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
+ 0 /* flags */);
+ if (applicationInfo != null) {
+ int predictionCategory = applicationInfo.category;
+ return getCategoryFromApplicationCategory(context, predictionCategory,
+ widgetComponentName);
+ }
}
}
return null;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 28eeb10..6aaa7d2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -17,10 +17,10 @@
import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
-import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.widget.picker.WidgetsListAdapter.VIEW_TYPE_WIDGETS_LIST;
import android.animation.Animator;
import android.content.Context;
@@ -57,19 +57,15 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.model.UserManagerState;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
import com.android.launcher3.views.StickyHeaderLayout;
-import com.android.launcher3.views.WidgetsEduView;
import com.android.launcher3.widget.BaseWidgetSheet;
import com.android.launcher3.widget.WidgetCell;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -93,8 +89,6 @@
WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
private static final long FADE_IN_DURATION = 150;
- private static final long EDUCATION_TIP_DELAY_MS = 200;
- private static final long EDUCATION_DIALOG_DELAY_MS = 500;
// The widget recommendation table can easily take over the entire screen on devices with small
// resolution or landscape on phone. This ratio defines the max percentage of content area that
@@ -117,36 +111,6 @@
new HashMap<>();
protected int mRecommendationsCurrentPage = 0;
protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
- @Nullable
- private ArrowTipView mLatestEducationalTip;
- private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
- new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (hasSeenEducationTip()) {
- removeOnLayoutChangeListener(this);
- return;
- }
-
- // Widgets are loaded asynchronously, We are adding a delay because we only want
- // to show the tip when the widget preview has finished loading and rendering in
- // this view.
- removeCallbacks(mShowEducationTipTask);
- postDelayed(mShowEducationTipTask, EDUCATION_TIP_DELAY_MS);
- }
- };
-
- private final Runnable mShowEducationTipTask = () -> {
- if (hasSeenEducationTip()) {
- removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
- return;
- }
- mLatestEducationalTip = showEducationTipOnViewIfPossible(getViewToShowEducationTip());
- if (mLatestEducationalTip != null) {
- removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
- }
- };
private final OnAttachStateChangeListener mBindScrollbarInSearchMode =
new OnAttachStateChangeListener() {
@@ -251,7 +215,6 @@
mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
onWidgetsBound();
- setUpEducationViewsIfNeeded();
}
protected void setupViews() {
@@ -816,10 +779,6 @@
@Override
protected void onCloseComplete() {
super.onCloseComplete();
- removeCallbacks(mShowEducationTipTask);
- if (mLatestEducationalTip != null) {
- mLatestEducationalTip.close(true);
- }
AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
}
@@ -959,36 +918,6 @@
return null;
}
- /** Shows education dialog for widgets. */
- private WidgetsEduView showEducationDialog() {
- LauncherPrefs.get(getContext()).put(WIDGETS_EDUCATION_DIALOG_SEEN, true);
- return WidgetsEduView.showEducationDialog(mActivityContext);
- }
-
- /** Returns {@code true} if education dialog has previously been shown. */
- protected boolean hasSeenEducationDialog() {
- return LauncherPrefs.get(getContext()).get(WIDGETS_EDUCATION_DIALOG_SEEN)
- || Utilities.isRunningInTestHarness();
- }
-
- protected void setUpEducationViewsIfNeeded() {
- if (!hasSeenEducationDialog()) {
- postDelayed(() -> {
- WidgetsEduView eduDialog = showEducationDialog();
- eduDialog.addOnCloseListener(() -> {
- if (!hasSeenEducationTip()) {
- addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
- // Call #requestLayout() to trigger layout change listener in order to show
- // arrow tip immediately if there is a widget to show it on.
- requestLayout();
- }
- });
- }, EDUCATION_DIALOG_DELAY_MS);
- } else if (!hasSeenEducationTip()) {
- addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
- }
- }
-
protected boolean isTwoPane() {
return false;
}
@@ -1094,10 +1023,35 @@
default:
break;
}
- mWidgetsListItemAnimator = new DefaultItemAnimator();
+ mWidgetsListItemAnimator = new DefaultItemAnimator() {
+ @Override
+ public boolean animateChange(RecyclerView.ViewHolder oldHolder,
+ RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft,
+ int toTop) {
+ // As we expand an item, the content / widgets list that appears (with add
+ // event) also gets change events as its previews load asynchronously. The
+ // super implementation of animateChange cancels the animations on it - breaking
+ // the "add animation". Instead, here, we skip "change" animation for content
+ // list - because we want it to either appear or disappear. And, the previews
+ // themselves have their own animation when loaded, so, we don't need change
+ // animations for them anyway. Below, we do-nothing.
+ if (oldHolder.getItemViewType() == VIEW_TYPE_WIDGETS_LIST) {
+ dispatchChangeStarting(oldHolder, true);
+ dispatchChangeFinished(oldHolder, true);
+ return true;
+ }
+ return super.animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft,
+ toTop);
+ }
+ };
// Disable change animations because it disrupts the item focus upon adapter item
// change.
mWidgetsListItemAnimator.setSupportsChangeAnimations(false);
+ // Make the moves a bit faster, so that the amount of time for which user sees the
+ // bottom-sheet background before "add" animation starts is less making it smoother.
+ mWidgetsListItemAnimator.setChangeDuration(90);
+ mWidgetsListItemAnimator.setMoveDuration(90);
+ mWidgetsListItemAnimator.setAddDuration(300);
}
private int getEmptySpaceHeight() {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index a7f7785..56352cc 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -160,6 +160,7 @@
WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
R.layout.widget_cell, tableRow, false);
// set up touch.
+ widget.setOnClickListener(mIconClickListener);
View preview = widget.findViewById(R.id.widget_preview_container);
preview.setOnClickListener(mIconClickListener);
preview.setOnLongClickListener(mIconLongClickListener);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index a565780..6dbad5c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -58,12 +58,13 @@
public WidgetsRecommendationTableLayout(Context context, AttributeSet attrs) {
super(context, attrs);
- // There are 1 row for title, 1 row for dimension and 2 rows for description.
+ // There are 1 row for title, 1 row for dimension and max 3 rows for description.
mWidgetsRecommendationTableVerticalPadding = 2 * getResources()
.getDimensionPixelSize(R.dimen.widget_recommendations_table_vertical_padding);
mWidgetCellVerticalPadding = 2 * getResources()
.getDimensionPixelSize(R.dimen.widget_cell_vertical_padding);
- mWidgetCellTextViewsHeight = 4 * getResources().getDimension(R.dimen.widget_cell_font_size);
+ mWidgetCellTextViewsHeight =
+ getResources().getDimension(R.dimen.widget_cell_title_line_height);
}
/** Sets a {@link android.view.View.OnLongClickListener} for all widget cells in this table. */
@@ -123,6 +124,7 @@
private WidgetCell addItemCell(ViewGroup parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(
getContext()).inflate(R.layout.widget_cell, parent, false);
+ widget.setOnClickListener(mWidgetCellOnClickListener);
View previewContainer = widget.findViewById(R.id.widget_preview_container);
previewContainer.setOnClickListener(mWidgetCellOnClickListener);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 2a2feed..f835e18 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -29,17 +29,20 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.Px;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.recyclerview.ViewHolderBinder;
import com.android.launcher3.util.PackageUserKey;
@@ -64,7 +67,7 @@
// This ratio defines the max percentage of content area that the recommendations can display
// with respect to the bottom sheet's height.
- private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.75f;
+ private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.60f;
private FrameLayout mSuggestedWidgetsContainer;
private WidgetsListHeader mSuggestedWidgetsHeader;
private PackageUserKey mSuggestedWidgetsPackageUserKey;
@@ -76,6 +79,7 @@
private boolean mOldIsSwipeToDismissInProgress;
private int mActivePage = -1;
+ @Nullable
private PackageUserKey mSelectedHeader;
public WidgetsTwoPaneSheet(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -129,7 +133,6 @@
mPrimaryWidgetListView.setClipToOutline(true);
onWidgetsBound();
- setUpEducationViewsIfNeeded();
// Set the fast scroller as not visible for two pane layout.
mFastScroller.setVisibility(GONE);
@@ -195,15 +198,21 @@
layoutParams.width = 0;
}
layoutParams.weight = layoutParams.width == 0 ? 0.33F : 0;
- leftPane.setLayoutParams(layoutParams);
- requestApplyInsets();
- if (mSelectedHeader != null) {
- if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
- mSuggestedWidgetsHeader.callOnClick();
- } else {
- getHeaderChangeListener().onHeaderChanged(mSelectedHeader);
+
+ post(() -> {
+ // The following calls all trigger requestLayout, so we post them to avoid
+ // calling requestLayout during a layout pass. This also fixes the related warnings
+ // in logcat.
+ leftPane.setLayoutParams(layoutParams);
+ requestApplyInsets();
+ if (mSelectedHeader != null) {
+ if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
+ mSuggestedWidgetsHeader.callOnClick();
+ } else {
+ getHeaderChangeListener().onHeaderChanged(mSelectedHeader);
+ }
}
- }
+ });
}
}
@@ -223,6 +232,10 @@
if (mSuggestedWidgetsContainer == null && mRecommendedWidgetsCount > 0) {
setupSuggestedWidgets(LayoutInflater.from(getContext()));
mSuggestedWidgetsHeader.callOnClick();
+ } else if (mSelectedHeader != null
+ && mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
+ // Reselect widget if we are reloading recommendations while it is currently showing.
+ selectWidgetCell(mWidgetRecommendationsContainer, getLastSelectedWidgetItem());
}
}
@@ -270,6 +283,16 @@
mRightPaneScrollView.setScrollY(0);
mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
+ final boolean isChangingHeaders = mSelectedHeader == null
+ || !mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey);
+ if (isChangingHeaders) {
+ // 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
+ // means a WidgetCell in the recommendations container may still be selected from
+ // the last time the recommendations were shown.
+ unselectWidgetCell(mWidgetRecommendationsContainer, getLastSelectedWidgetItem());
+ }
mSelectedHeader = mSuggestedWidgetsPackageUserKey;
});
mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
@@ -358,6 +381,8 @@
return new HeaderChangeListener() {
@Override
public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
+ final boolean isSameHeader = mSelectedHeader != null
+ && mSelectedHeader.equals(selectedHeader);
mSelectedHeader = selectedHeader;
WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
.getSelectedAppWidgets(selectedHeader);
@@ -385,11 +410,20 @@
contentEntryToBind,
ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
Collections.EMPTY_LIST);
+ if (isSameHeader) {
+ // Reselect the last selected widget if we are reloading the same header.
+ selectWidgetCell(widgetsRowViewHolder.tableContainer,
+ getLastSelectedWidgetItem());
+ }
widgetsRowViewHolder.mDataCallback = data -> {
mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
contentEntryToBind,
ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
Collections.singletonList(data));
+ if (isSameHeader) {
+ selectWidgetCell(widgetsRowViewHolder.tableContainer,
+ getLastSelectedWidgetItem());
+ }
};
mRightPane.removeAllViews();
mRightPane.addView(widgetsRowViewHolder.itemView);
@@ -402,6 +436,24 @@
};
}
+ private static void selectWidgetCell(ViewGroup parent, WidgetItem item) {
+ if (parent == null || item == null) return;
+ WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell wc
+ && wc.matchesItem(item));
+ if (cell != null && !cell.isShowingAddButton()) {
+ cell.callOnClick();
+ }
+ }
+
+ private static void unselectWidgetCell(ViewGroup parent, WidgetItem item) {
+ if (parent == null || item == null) return;
+ WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell wc
+ && wc.matchesItem(item));
+ if (cell != null && cell.isShowingAddButton()) {
+ cell.hideAddButton(/* animate= */ false);
+ }
+ }
+
@Override
public void setInsets(Rect insets) {
super.setInsets(insets);
diff --git a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
index 5e0e203..edaf474 100644
--- a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
+++ b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
@@ -31,6 +31,7 @@
/** An utility class which groups {@link WidgetItem}s into a table. */
public final class WidgetsTableUtils {
+ private static final int MAX_ITEMS_IN_ROW = 3;
/**
* Groups widgets in the following order:
@@ -125,7 +126,8 @@
widgetItemsAtRow.add(widgetItem);
containerSizeForRow = containerSize;
currentRowWidth = containerWidth;
- } else if ((currentRowWidth + containerWidth) <= rowPx
+ } else if (widgetItemsAtRow.size() < MAX_ITEMS_IN_ROW
+ && (currentRowWidth + containerWidth) <= rowPx
&& widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))
&& containerSize.equals(containerSizeForRow)) {
// Group items in the same row if
diff --git a/tests/Android.bp b/tests/Android.bp
index 3822ff8..11177de 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -23,7 +23,8 @@
srcs: [
"src/**/*.java",
"src/**/*.kt",
- ":launcher3-robo-src",
+ "multivalentTests/src/**/*.java",
+ "multivalentTests/src/**/*.kt",
],
exclude_srcs: [
":launcher-non-quickstep-tests-src",
@@ -37,6 +38,8 @@
srcs: [
"multivalentTests/src/**/*.java",
"multivalentTests/src/**/*.kt",
+ "src_deviceless/**/*.java",
+ "src_deviceless/**/*.kt",
],
}
@@ -102,6 +105,7 @@
android_library {
name: "Launcher3TestResources",
resource_dirs: ["res"],
+ asset_dirs: ["assets"],
// TODO(b/319712088): re-enable use_resource_processor
use_resource_processor: false,
}
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 27dd2a9..8c5195e 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -319,6 +319,15 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
+ <activity-alias android:name="ActivityNoLabel"
+ android:label=""
+ android:exported="true"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity-alias>
<activity-alias android:name="MaxShortcutsActivity"
android:label="TestActivityMaxShortcuts"
android:exported="true"
@@ -403,5 +412,9 @@
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
+
+ <property
+ android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"
+ android:value="true"/>
</application>
</manifest>
diff --git a/tests/Launcher3Tests.xml b/tests/Launcher3Tests.xml
index 29c34be..270a610 100644
--- a/tests/Launcher3Tests.xml
+++ b/tests/Launcher3Tests.xml
@@ -44,6 +44,8 @@
<option name="run-command" value="settings put global airplane_mode_on 1" />
<option name="run-command" value="am broadcast -a android.intent.action.AIRPLANE_MODE" />
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
+
<option name="run-command" value="settings put system pointer_location 1" />
<option name="run-command" value="settings put system show_touches 1" />
</target_preparer>
diff --git a/tests/OWNERS b/tests/OWNERS
index b5ee7d7..6b8643c 100644
--- a/tests/OWNERS
+++ b/tests/OWNERS
@@ -3,4 +3,3 @@
sunnygoyal@google.com
winsonc@google.com
hyunyoungs@google.com
-mateuszc@google.com
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 fea0330..c3b7a2a 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -170,22 +170,12 @@
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String TWO_NEXUS_LAUNCHER_ACTIVITY_WHILE_UNLOCKING = "b/273347463";
- public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
public static final String ICON_MISSING = "b/282963545";
- public static final String OVERVIEW_OVER_HOME = "b/279059025";
public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
- public static final String GET_FROM_RECENTS_FAILURE = "b/321775748";
- public static final String SUCCESSFUL_GESTURE_MISMATCH_EVENTS = "b/324940434";
public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
- public static final String TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE = "b/326073471";
public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
- public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
- public static final String UPDATE_OVERVIEW_TARGETS_RUNNING_LATE = "b/321775748";
-
- public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
- public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
- public static final String REQUEST_IS_EMULATE_DISPLAY_RUNNING = "is-emulate-display-running";
- public static final String REQUEST_EMULATE_PRINT_DEVICE = "emulate-print-device";
+ public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
+ public static final String CLOCK_ICON_DRAWABLE_LEAKING = "b/319168409";
public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
diff --git a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
similarity index 97%
rename from tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
index 13dfd5e..c32461e 100644
--- a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
@@ -22,6 +22,8 @@
import android.view.View
import androidx.core.view.get
import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
import com.android.launcher3.CellLayout
import com.android.launcher3.celllayout.board.CellLayoutBoard
import com.android.launcher3.celllayout.board.IconPoint
@@ -34,6 +36,7 @@
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
private class HotseatReorderTestCase(
val startBoard: CellLayoutBoard,
@@ -44,6 +47,8 @@
}
}
+@SmallTest
+@RunWith(AndroidJUnit4::class)
class HotseatReorderUnitTest {
private val applicationContext: Context =
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index 0ff7c20..8a9711d 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -215,9 +215,11 @@
testCase.spanX, testCase.spanY, testCase.minSpanX, testCase.minSpanY,
isMultiCellLayout);
assertEquals("should be a valid solution", solution.isSolution, testCase.isValidSolution);
+ Log.d(TAG, "test case:" + testCase);
if (testCase.isValidSolution) {
CellLayoutBoard finishBoard = boardFromSolution(solution,
testCase.startBoard.getWidth(), testCase.startBoard.getHeight());
+ Log.d(TAG, "finishBoard case:" + finishBoard);
assertTrue("End result and test case result board doesn't match ",
finishBoard.compareTo(testCase.endBoard) == 0);
}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
index 0bec1b2..a9355ec 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
@@ -141,11 +141,14 @@
ReorderPreviewAnimation.MODE_PREVIEW,
AnimationValues(dx = 0, dy = 0, scale = 100)
)
- testAnimationAtGivenProgress(
- PREVIEW_DURATION * 99,
- ReorderPreviewAnimation.MODE_PREVIEW,
- AnimationValues(dx = 5, dy = -10, scale = 96)
- )
+ // (b/339313407) Temporarily disable this test as the behavior is
+ // inconsistent between Soong & Gradle builds.
+ //
+ // testAnimationAtGivenProgress(
+ // PREVIEW_DURATION * 99,
+ // ReorderPreviewAnimation.MODE_PREVIEW,
+ // AnimationValues(dx = 5, dy = -10, scale = 96)
+ // )
testAnimationAtGivenProgress(
PREVIEW_DURATION * 98,
ReorderPreviewAnimation.MODE_PREVIEW,
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderTestCase.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderTestCase.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/ReorderTestCase.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderTestCase.java
diff --git a/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java b/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
index fbbfb2a..58dce0b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
@@ -38,7 +38,8 @@
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.util.LauncherMultivalentJUnit;
import org.junit.Before;
import org.junit.Test;
@@ -51,8 +52,8 @@
* Tests for FastBitmapDrawable.
*/
@SmallTest
+@RunWith(LauncherMultivalentJUnit.class)
@UiThreadTest
-@RunWith(AndroidJUnit4.class)
public class FastBitmapDrawableTest {
private static final float EPSILON = 0.00001f;
diff --git a/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt b/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
index 130dfad..713d4d5 100644
--- a/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
@@ -2,8 +2,8 @@
import androidx.core.util.isEmpty
import androidx.test.annotation.UiThreadTest
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.launcher3.util.LauncherMultivalentJUnit
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -11,7 +11,7 @@
/** Unit test for [ColdRebootStartupLatencyLogger]. */
@SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(LauncherMultivalentJUnit::class)
class StartupLatencyLoggerTest {
private val underTest = ColdRebootStartupLatencyLogger()
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
rename to tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index 90ded10..b83349e 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -37,6 +37,9 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.ViewGroup;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
@@ -52,6 +55,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
/**
@@ -61,6 +65,8 @@
* two lines, and this is enough to ensure whether the string should be specifically wrapped onto
* the second line and to ensure truncation.
*/
+@SmallTest
+@RunWith(AndroidJUnit4.class)
public class BubbleTextViewTest {
@Rule public final SetFlagsRule mSetFlagsRule =
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index 0009a4e..f18c02b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -44,25 +44,16 @@
import android.test.mock.MockContentResolver;
import android.util.ArrayMap;
-import androidx.annotation.NonNull;
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.LauncherModel.ModelUpdateTask;
-import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
import com.android.launcher3.testing.TestInformationProvider;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
-import com.android.launcher3.util.window.WindowManagerProxy;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -72,7 +63,6 @@
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
/**
* Utility class to help manage Launcher Model and related objects for test.
@@ -121,17 +111,9 @@
public synchronized BgDataModel getBgDataModel() {
if (mDataModel == null) {
- getModel().enqueueModelUpdateTask(new ModelUpdateTask() {
- @Override
- public void init(@NonNull LauncherAppState app, @NonNull LauncherModel model,
- @NonNull BgDataModel dataModel, @NonNull AllAppsList allAppsList,
- @NonNull Executor uiExecutor) {
- mDataModel = dataModel;
- }
-
- @Override
- public void run() { }
- });
+ getModel().enqueueModelUpdateTask((taskController, dataModel, apps) ->
+ mDataModel = dataModel);
+ runOnExecutorSync(Executors.MODEL_EXECUTOR, () -> { });
}
return mDataModel;
}
@@ -233,13 +215,7 @@
private final File mDbDir;
public SandboxModelContext() {
- super(ApplicationProvider.getApplicationContext(),
- UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
- LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
- DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
- SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
- LockedUserState.INSTANCE, WallpaperColorHints.INSTANCE,
- ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
+ super(ApplicationProvider.getApplicationContext());
// System settings cache content provider. Ensure that they are statically initialized
Settings.Secure.getString(
@@ -254,18 +230,13 @@
}
@Override
- protected <T> T createObject(MainThreadInitializedObject<T> object) {
+ public <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
if (object == LauncherAppState.INSTANCE) {
return (T) new LauncherAppState(this, null /* iconCacheFileName */);
}
return super.createObject(object);
}
- public SandboxModelContext allow(MainThreadInitializedObject object) {
- mAllowedObjects.add(object);
- return this;
- }
-
@Override
public File getDatabasePath(String name) {
if (!mDbDir.exists()) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherMultivalentJUnit.kt b/tests/multivalentTests/src/com/android/launcher3/util/LauncherMultivalentJUnit.kt
new file mode 100644
index 0000000..e8560af
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherMultivalentJUnit.kt
@@ -0,0 +1,79 @@
+/*
+ * 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 androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.collect.ImmutableList
+import java.util.Locale
+import kotlin.annotation.AnnotationRetention.RUNTIME
+import kotlin.annotation.AnnotationTarget.CLASS
+import org.junit.runner.Runner
+import org.junit.runners.Suite
+
+/**
+ * A custom runner for multivalent tests with launcher specific features
+ * 1) Adds support for @UiThread annotations in deviceless tests
+ * 2) Allows emulating multiple devices when running in deviceless mode
+ */
+class LauncherMultivalentJUnit(klass: Class<*>?) : Suite(klass, ImmutableList.of()) {
+
+ val runners: List<Runner> =
+ (testClass.getAnnotation(EmulatedDevices::class.java)?.value ?: emptyArray()).let { devices
+ ->
+ if (!isRunningInRobolectric) {
+ return@let null
+ }
+ try {
+ (testClass.javaClass.classLoader.loadClass(ROBOLECTRIC_RUNNER) as Class<Runner>)
+ .getConstructor(Class::class.java, String::class.java)
+ .let { ctor ->
+ if (devices.isEmpty()) listOf(ctor.newInstance(testClass.javaClass, null))
+ else devices.map { ctor.newInstance(testClass.javaClass, it) }
+ }
+ } catch (e: Exception) {
+ null
+ }
+ }
+ ?: listOf(AndroidJUnit4(testClass.javaClass))
+
+ override fun getChildren() = runners
+
+ /**
+ * Annotation to be added to a test so run it on a list of emulated devices for deviceless test
+ */
+ @Retention(RUNTIME) @Target(CLASS) annotation class EmulatedDevices(val value: Array<String>)
+
+ companion object {
+ private const val ROBOLECTRIC_RUNNER = "com.android.launcher3.util.RobolectricDeviceRunner"
+
+ val isRunningInRobolectric: Boolean
+ get() =
+ if (
+ System.getProperty("java.runtime.name")
+ .lowercase(Locale.getDefault())
+ .contains("android")
+ ) {
+ false
+ } else {
+ try {
+ // Check if robolectric runner exists
+ Class.forName("org.robolectric.RobolectricTestRunner") != null
+ } catch (e: ClassNotFoundException) {
+ false
+ }
+ }
+ }
+}
diff --git a/tests/res/layout/utilities_test_view.xml b/tests/res/layout/utilities_test_view.xml
new file mode 100644
index 0000000..dc2a515
--- /dev/null
+++ b/tests/res/layout/utilities_test_view.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/root_view">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/mid_view">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/child_view" />
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/shared/com/android/launcher3/testing/OWNERS b/tests/shared/com/android/launcher3/testing/OWNERS
new file mode 100644
index 0000000..02e8ebc
--- /dev/null
+++ b/tests/shared/com/android/launcher3/testing/OWNERS
@@ -0,0 +1,4 @@
+vadimt@google.com
+sunnygoyal@google.com
+winsonc@google.com
+hyunyoungs@google.com
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 577334b..e378733 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -300,18 +300,13 @@
smallestScreenWidthDp = min(screenWidthDp, screenHeightDp)
}
val configurationContext = runningContext.createConfigurationContext(config)
- context =
- SandboxContext(
- configurationContext,
- DisplayController.INSTANCE,
- WindowManagerProxy.INSTANCE,
- LauncherPrefs.INSTANCE
- )
+ context = SandboxContext(configurationContext)
context.putObject(DisplayController.INSTANCE, displayController)
context.putObject(WindowManagerProxy.INSTANCE, windowManagerProxy)
context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
whenever(launcherPrefs.get(LauncherPrefs.TASKBAR_PINNING)).thenReturn(false)
+ whenever(launcherPrefs.get(LauncherPrefs.TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(true)
val info = spy(DisplayController.Info(context, windowManagerProxy, perDisplayBoundsCache))
whenever(displayController.info).thenReturn(info)
whenever(info.isTransientTaskbar).thenReturn(isGestureMode)
diff --git a/tests/src/com/android/launcher3/UtilitiesKtTest.kt b/tests/src/com/android/launcher3/UtilitiesKtTest.kt
index dd83871..9aa0369 100644
--- a/tests/src/com/android/launcher3/UtilitiesKtTest.kt
+++ b/tests/src/com/android/launcher3/UtilitiesKtTest.kt
@@ -20,15 +20,14 @@
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER
import com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER
import com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree
import com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree
-import com.android.launcher3.util.ActivityContextWrapper
-import com.android.launcher3.views.WidgetsEduView
+import com.android.launcher3.tests.R
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -38,17 +37,17 @@
@RunWith(AndroidJUnit4::class)
class UtilitiesKtTest {
- val context: Context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+ val context: Context = InstrumentationRegistry.getInstrumentation().context
- private lateinit var rootView: WidgetsEduView
+ private lateinit var rootView: ViewGroup
private lateinit var midView: ViewGroup
private lateinit var childView: View
@Before
fun setup() {
rootView =
- LayoutInflater.from(context).inflate(R.layout.widgets_edu, null) as WidgetsEduView
- midView = rootView.requireViewById(R.id.edu_view)
- childView = rootView.requireViewById(R.id.edu_header)
+ LayoutInflater.from(context).inflate(R.layout.utilities_test_view, null) as ViewGroup
+ midView = rootView.requireViewById(R.id.mid_view)
+ childView = rootView.requireViewById(R.id.child_view)
}
@Test
diff --git a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
index 423ca24..d2238ff 100644
--- a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
+++ b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
@@ -98,7 +98,7 @@
when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
.thenAnswer(answer(this::addPrivateSpaceHeader));
when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps(any()))
.thenReturn(iteminfo -> iteminfo.componentName == null
|| !iteminfo.componentName.getPackageName()
.equals("com.android.launcher3.tests.camera"));
@@ -127,7 +127,7 @@
when(mPrivateProfileManager.addSystemAppsDivider(any()))
.thenAnswer(answer(this::addSystemAppsDivider));
when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps(mContext))
.thenReturn(iteminfo -> iteminfo.componentName == null
|| !iteminfo.componentName.getPackageName()
.equals("com.android.launcher3.tests.camera"));
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 2a4d21d..4cd2a07 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -167,7 +167,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/320703862
public void transitioningToUnlocked_resetCallsPostUnlock() throws Exception {
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
@@ -185,7 +184,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
public void transitioningToLocked_resetCallsExecuteLock() throws Exception {
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
@@ -204,6 +202,7 @@
}
@Test
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/339109319
public void openPrivateSpaceSettings_triggersCorrectIntent() {
Intent expectedIntent = ApiWrapper.INSTANCE.get(mContext).getPrivateSpaceSettingsIntent();
ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
index 9363ce8..512b2ac 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -71,6 +71,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.function.Predicate;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -279,10 +280,8 @@
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
- .thenReturn(iteminfo -> iteminfo.componentName == null
- || !iteminfo.componentName.getPackageName()
- .equals(CAMERA_PACKAGE_NAME));
+ doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+ .splitIntoUserInstalledAndSystemApps(any());
doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
.addPrivateSpaceHeader(any());
@@ -316,10 +315,8 @@
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
- .thenReturn(iteminfo -> iteminfo.componentName == null
- || !iteminfo.componentName.getPackageName()
- .equals(CAMERA_PACKAGE_NAME));
+ doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+ .splitIntoUserInstalledAndSystemApps(any());
doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
.addPrivateSpaceHeader(any());
@@ -353,10 +350,8 @@
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
- .thenReturn(iteminfo -> iteminfo.componentName == null
- || !iteminfo.componentName.getPackageName()
- .equals(CAMERA_PACKAGE_NAME));
+ doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+ .splitIntoUserInstalledAndSystemApps(any());
doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
.addPrivateSpaceHeader(any());
@@ -390,10 +385,8 @@
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
- .thenReturn(iteminfo -> iteminfo.componentName == null
- || !iteminfo.componentName.getPackageName()
- .equals(CAMERA_PACKAGE_NAME));
+ doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+ .splitIntoUserInstalledAndSystemApps(any());
doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
@@ -465,4 +458,10 @@
}
return appInfos.toArray(AppInfo[]::new);
}
+
+ private Predicate<AppInfo> splitIntoUserInstalledAndSystemApps() {
+ return iteminfo -> iteminfo.componentName == null
+ || !iteminfo.componentName.getPackageName()
+ .equals(CAMERA_PACKAGE_NAME);
+ }
}
diff --git a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
index 389d027..28a1325 100644
--- a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
+++ b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
@@ -40,7 +40,6 @@
import com.android.launcher3.tapl.WidgetResizeFrame;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.ModelTestExtensions;
-import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.After;
@@ -238,7 +237,6 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/330019521
public void simpleReorder() throws Exception {
runTestCaseMap(getTestMap("ReorderWidgets/simple_reorder_case"),
"push_reorder_case");
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index d64d096..1c41ded 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -21,8 +21,6 @@
import static com.android.launcher3.util.TestConstants.AppNames.PHOTOS_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
-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.assertNotNull;
@@ -43,8 +41,6 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
-import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.Test;
@@ -67,9 +63,6 @@
*/
@Test
@PortraitLandscape
- @ScreenRecord
- // Staging; will be promoted to presubmit if stable
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
@PlatinumTest(focusArea = "launcher")
public void testDragToFolder() {
// TODO: add the use case to drag an icon to an existing folder. Currently it either fails
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index b7933c8..362596c 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -115,7 +115,6 @@
@Test
@PortraitLandscape
@PlatinumTest(focusArea = "launcher")
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/326130648
public void testUninstallFromAllApps() throws Exception {
installDummyAppAndWaitForUIUpdate();
try {
@@ -178,6 +177,8 @@
*/
@Test
@PortraitLandscape
+ @ScreenRecordRule.ScreenRecord // b/338869019
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/338869019
public void testAddDeleteShortcutOnHotseat() {
mLauncher.getWorkspace()
.deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
diff --git a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java b/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
index 715a1f8..7242e9c 100644
--- a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
+++ b/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
@@ -30,6 +30,7 @@
import android.view.animation.PathInterpolator;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.CellLayout;
@@ -50,7 +51,8 @@
@Mock
CellLayout mCellLayout;
- private final PreviewBackground mPreviewBackground = new PreviewBackground();
+ private final PreviewBackground mPreviewBackground =
+ new PreviewBackground(InstrumentationRegistry.getInstrumentation().getContext());
@Before
public void setUp() {
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index d3a6355..328558d 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -8,8 +8,6 @@
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
-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.assertFalse;
@@ -98,7 +96,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325283522
public void testCacheUpdate_update_apps() {
// Run on model executor so that no other task runs in the middle.
runOnExecutorSync(MODEL_EXECUTOR, () -> {
@@ -129,7 +126,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325283522
public void testSessionUpdate_updates_pending_apps() {
// Run on model executor so that no other task runs in the middle.
runOnExecutorSync(MODEL_EXECUTOR, () -> {
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index 2e209a4..c4a4c9b 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -24,13 +24,11 @@
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.LauncherModelHelper.*
import com.android.launcher3.util.TestUtil
-import com.android.launcher3.util.rule.TestStabilityRule
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
@@ -58,8 +56,6 @@
TEST_ACTIVITY14
)
- @get:Rule(order = 0) val testStabilityRule = TestStabilityRule()
-
@Before
fun setUp() {
modelHelper = LauncherModelHelper()
@@ -91,9 +87,6 @@
@Test
@Throws(Exception::class)
- @TestStabilityRule.Stability(
- flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
- ) // b/319923578
fun folderLoadedWithHighRes_max_3x3() {
val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
idp.numFolderColumns = intArrayOf(3, 3, 3, 3)
@@ -107,9 +100,6 @@
@Test
@Throws(Exception::class)
- @TestStabilityRule.Stability(
- flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
- ) // b/319923578
fun folderLoadedWithHighRes_max_4x4() {
val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
idp.numFolderColumns = intArrayOf(4, 4, 4, 4)
@@ -123,10 +113,6 @@
@Test
@Throws(Exception::class)
- // Stress tests are long. We permanently demote them from presubmit to match the presubmit SLO.
- @TestStabilityRule.Stability(
- flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
- ) // b/319923578
fun folderLoadedWithHighRes_differentFolderConfigurations() {
val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
idp.numFolderColumns = intArrayOf(4, 3, 4, 4)
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 56ac960..b4945d7 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -79,6 +79,7 @@
private LauncherModelHelper mModelHelper;
private LauncherAppState mApp;
+ private PackageManagerHelper mPmHelper;
private MatrixCursor mCursor;
private InvariantDeviceProfile mIDP;
@@ -92,6 +93,7 @@
mContext = mModelHelper.sandboxContext;
mIDP = InvariantDeviceProfile.INSTANCE.get(mContext);
mApp = LauncherAppState.getInstance(mContext);
+ mPmHelper = PackageManagerHelper.INSTANCE.get(mContext);
mCursor = new MatrixCursor(new String[] {
ICON, TITLE, _ID, CONTAINER, ITEM_TYPE,
@@ -101,7 +103,7 @@
});
UserManagerState ums = new UserManagerState();
- mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, null);
+ mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, mPmHelper, null);
ums.allUsers.put(0, Process.myUserHandle());
}
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 5731e2a..28a001f 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -56,7 +56,7 @@
@Spy private var userManagerState: UserManagerState? = UserManagerState()
- @get:Rule val setFlagsRule = SetFlagsRule().apply { initAllFlagsToReleaseConfigDefault() }
+ @get:Rule val setFlagsRule = SetFlagsRule()
@Before
fun setup() {
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index c2e73fc..6bbcf85 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -24,18 +24,29 @@
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 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.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
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_WIDGET_PROVIDER
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.PROFILE_DELETED
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.IconRequestInfo
import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.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
@@ -43,11 +54,14 @@
import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
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.Test
+import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.RETURNS_DEEP_STUBS
import org.mockito.Mockito.mock
@@ -56,8 +70,10 @@
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
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
class WorkspaceItemProcessorTest {
@@ -73,29 +89,31 @@
@Mock private lateinit var mockUserManagerState: UserManagerState
@Mock private lateinit var mockWidgetInflater: WidgetInflater
- private lateinit var intent: Intent
- private lateinit var userHandle: UserHandle
- private lateinit var iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>
- private lateinit var componentName: ComponentName
- private lateinit var unlockedUsersArray: LongSparseArray<Boolean>
- private lateinit var keyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo>
- private lateinit var installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>
- private lateinit var allDeepShortcuts: MutableList<ShortcutInfo>
+ 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() {
- userHandle = UserHandle(0)
+ mUserHandle = UserHandle(0)
mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
- iconRequestInfos = mutableListOf(mockIconRequestInfo)
mockWorkspaceInfo = mock<WorkspaceItemInfo>()
mockBgDataModel = mock<BgDataModel>()
- componentName = ComponentName("package", "class")
- unlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
+ mComponentName = ComponentName("package", "class")
+ mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
intent =
Intent().apply {
- component = componentName
+ component = mComponentName
`package` = "pkg"
putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
}
@@ -112,17 +130,17 @@
}
mockPmHelper =
mock<PackageManagerHelper>().apply {
- whenever(getAppLaunchIntent(componentName.packageName, userHandle))
+ whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
.thenReturn(intent)
}
mockLauncherApps =
mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
- whenever(isActivityEnabled(componentName, userHandle)).thenReturn(true)
+ whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+ whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
}
mockCursor =
mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
- user = userHandle
+ user = mUserHandle
itemType = ITEM_TYPE_APPLICATION
id = 1
restoreFlag = 1
@@ -137,15 +155,18 @@
mockUserCache =
mock<UserCache>().apply {
val userIconInfo =
- mock<UserIconInfo>().apply() { whenever(isPrivate).thenReturn(false) }
+ mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
whenever(getUserInfo(any())).thenReturn(userIconInfo)
}
mockUserManagerState = mock<UserManagerState>()
mockWidgetInflater = mock<WidgetInflater>()
- keyToPinnedShortcutsMap = mutableMapOf()
- installingPkgs = hashMapOf()
- allDeepShortcuts = mutableListOf()
+ mKeyToPinnedShortcutsMap = mutableMapOf()
+ mInstallingPkgs = hashMapOf()
+ mAllDeepShortcuts = mutableListOf()
+ mWidgetProvidersMap = mutableMapOf()
+ mIconRequestInfos = mutableListOf()
+ mPendingPackages = mutableSetOf()
}
/**
@@ -159,18 +180,18 @@
userCache: UserCache = mockUserCache,
userManagerState: UserManagerState = mockUserManagerState,
launcherApps: LauncherApps = mockLauncherApps,
- shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = keyToPinnedShortcutsMap,
+ shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap,
app: LauncherAppState = mockAppState,
bgDataModel: BgDataModel = mockBgDataModel,
- widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mutableMapOf(),
+ widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap,
widgetInflater: WidgetInflater = mockWidgetInflater,
pmHelper: PackageManagerHelper = mockPmHelper,
- iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf(),
+ iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mIconRequestInfos,
isSdCardReady: Boolean = false,
- pendingPackages: MutableSet<PackageUserKey> = mutableSetOf(),
- unlockedUsers: LongSparseArray<Boolean> = unlockedUsersArray,
- installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf(),
- allDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
+ pendingPackages: MutableSet<PackageUserKey> = mPendingPackages,
+ unlockedUsers: LongSparseArray<Boolean> = mUnlockedUsersArray,
+ installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = mInstallingPkgs,
+ allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts
) =
WorkspaceItemProcessor(
c = cursor,
@@ -241,8 +262,8 @@
fun `When app has empty String target package then mark deleted`() {
// Given
- componentName = ComponentName("", "")
- intent.component = componentName
+ mComponentName = ComponentName("", "")
+ intent.component = mComponentName
intent.`package` = ""
// When
@@ -267,7 +288,7 @@
.isEqualTo(0)
// currently gets marked restored twice, although markRestore() has check for restoreFlag
verify(mockCursor, times(2)).markRestored()
- assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+ assertThat(mIconRequestInfos).containsExactly(mockIconRequestInfo)
verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
}
@@ -277,12 +298,12 @@
// Given
mockLauncherApps =
mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
- whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+ whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+ whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(false)
}
mockPmHelper =
mock<PackageManagerHelper>().apply {
- whenever(getAppLaunchIntent(componentName.packageName, userHandle))
+ whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
.thenReturn(intent)
}
@@ -295,7 +316,7 @@
.that(mockCursor.restoreFlag)
.isEqualTo(0)
verify(mockCursor.updater().put(Favorites.INTENT, intent.toUri(0))).commit()
- assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+ assertThat(mIconRequestInfos).containsExactly(mockIconRequestInfo)
verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
}
@@ -305,12 +326,13 @@
// Given
mockLauncherApps =
mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
- whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+ whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+ whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(false)
}
mockPmHelper =
mock<PackageManagerHelper>().apply {
- whenever(getAppLaunchIntent(componentName.packageName, userHandle)).thenReturn(null)
+ whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
+ .thenReturn(null)
}
// When
@@ -349,20 +371,20 @@
whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
}
val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
- keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
- iconRequestInfos = mutableListOf()
+ mKeyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+ mIconRequestInfos = mutableListOf()
// When
itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = mAllDeepShortcuts)
itemProcessorUnderTest.processItem()
// Then
assertWithMessage("item restoreFlag should be set to 0")
.that(mockCursor.restoreFlag)
.isEqualTo(0)
- assertThat(iconRequestInfos).isEmpty()
- assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+ assertThat(mIconRequestInfos).isEmpty()
+ assertThat(mAllDeepShortcuts).containsExactly(expectedShortcutInfo)
verify(mockCursor).markRestored()
verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
}
@@ -372,8 +394,8 @@
// Given
mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
- iconRequestInfos = mutableListOf()
- keyToPinnedShortcutsMap = hashMapOf()
+ mIconRequestInfos = mutableListOf()
+ mKeyToPinnedShortcutsMap = hashMapOf()
// When
itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
@@ -383,7 +405,7 @@
assertWithMessage("item restoreFlag should be set to 0")
.that(mockCursor.restoreFlag)
.isEqualTo(0)
- assertThat(iconRequestInfos).isEmpty()
+ assertThat(mIconRequestInfos).isEmpty()
verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
verify(mockCursor)
.markDeleted(
@@ -408,25 +430,25 @@
whenever(disabledReason).thenReturn(0)
whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
}
- iconRequestInfos = mutableListOf()
+ mIconRequestInfos = mutableListOf()
// Make sure shortcuts map has expected key from expected package
- intent.`package` = componentName.packageName
+ intent.`package` = mComponentName.packageName
val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
- keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+ mKeyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
// set intent package back to null to test scenario
intent.`package` = null
// When
itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = mAllDeepShortcuts)
itemProcessorUnderTest.processItem()
// Then
assertWithMessage("item restoreFlag should be set to 0")
.that(mockCursor.restoreFlag)
.isEqualTo(0)
- assertThat(iconRequestInfos).isEmpty()
- assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+ assertThat(mIconRequestInfos).isEmpty()
+ assertThat(mAllDeepShortcuts).containsExactly(expectedShortcutInfo)
verify(mockCursor).markRestored()
verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
}
@@ -478,4 +500,346 @@
assertThat(actualFolderInfo.options).isEqualTo(expectedFolderInfo.options)
verify(mockCursor).checkAndAddItem(actualFolderInfo, mockBgDataModel, null)
}
+
+ @Test
+ fun `When valid TYPE_REAL App Widget then add item`() {
+
+ // Given
+ val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+ val expectedComponentName =
+ ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
+ val expectedRestoreStatus = FLAG_UI_NOT_READY
+ 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 expectedWidgetInfo =
+ LauncherAppWidgetInfo().apply {
+ appWidgetId = expectedAppWidgetId
+ providerName = ComponentName.unflattenFromString(expectedProvider)
+ restoreStatus = expectedRestoreStatus
+ }
+ val expectedWidgetProviderInfo =
+ mock<LauncherAppWidgetProviderInfo>().apply {
+ provider = ComponentName.unflattenFromString(expectedProvider)
+ whenever(user).thenReturn(mUserHandle)
+ }
+ val inflationResult =
+ WidgetInflater.InflationResult(
+ type = WidgetInflater.TYPE_REAL,
+ widgetInfo = expectedWidgetProviderInfo
+ )
+ 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 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)
+ }
+ val expectedComponentKey =
+ ComponentKey(expectedWidgetProviderInfo.provider, expectedWidgetProviderInfo.user)
+ assertThat(mWidgetProvidersMap[expectedComponentKey]).isEqualTo(expectedWidgetProviderInfo)
+ }
+
+ @Test
+ fun `When valid Pending Widget then checkAndAddItem`() {
+
+ // Given
+ 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("com.google.android.testApp/com.android.testApp.testAppProvider")
+ whenever(appWidgetId).thenReturn(0)
+ whenever(spanX).thenReturn(2)
+ whenever(spanY).thenReturn(1)
+ whenever(options).thenReturn(0)
+ whenever(appWidgetSource).thenReturn(20)
+ whenever(applyCommonProperties(any())).thenCallRealMethod()
+ }
+ val mockProviderInfo =
+ mock<LauncherAppWidgetProviderInfo>().apply {
+ provider = mock()
+ whenever(user).thenReturn(UserHandle(1))
+ }
+ val inflationResult =
+ WidgetInflater.InflationResult(
+ type = WidgetInflater.TYPE_PENDING,
+ widgetInfo = mockProviderInfo
+ )
+ mockWidgetInflater =
+ mock<WidgetInflater>().apply {
+ whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+ }
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockCursor).checkAndAddItem(any(), any())
+ }
+
+ @Test
+ fun `When Unrestored Pending App Widget then mark deleted`() {
+
+ // Given
+ val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+ 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)
+ }
+ val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
+
+ // When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockCursor)
+ .markDeleted(
+ "processWidget: Unrestored Pending widget removed: id=1, appWidgetId=0, component=$expectedComponentName, restoreFlag:=4",
+ LauncherRestoreEventLogger.RestoreError.APP_NOT_INSTALLED
+ )
+ }
+
+ @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"
+ 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)
+ container = CONTAINER_DESKTOP
+ whenever(spanX).thenReturn(2)
+ whenever(spanY).thenReturn(1)
+ whenever(appWidgetProvider).thenReturn(expectedProvider)
+ whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+ whenever(applyCommonProperties(any())).thenCallRealMethod()
+ }
+ mInstallingPkgs = hashMapOf()
+ val inflationResult =
+ WidgetInflater.InflationResult(
+ type = WidgetInflater.TYPE_DELETE,
+ widgetInfo = null,
+ reason = "test_delete_reason",
+ restoreErrorType = MISSING_WIDGET_PROVIDER
+ )
+ mockWidgetInflater =
+ mock<WidgetInflater>().apply {
+ whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+ }
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockCursor).markDeleted(inflationResult.reason, inflationResult.restoreErrorType)
+ }
}
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index e459956..dc8c17a 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -30,6 +30,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -244,7 +245,6 @@
SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
.getShortcut(mTestContext, mAppInfo, mView);
- verify(mPrivateProfileManager, times(2)).getProfileUser();
assertNull(systemShortcut);
}
@@ -266,8 +266,7 @@
SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
.getShortcut(mTestContext, mAppInfo, mView);
- verify(mPrivateProfileManager, times(3)).getProfileUser();
- verify(mPrivateProfileManager).isEnabled();
+ verify(mPrivateProfileManager, atLeast(1)).isEnabled();
assertNotNull(systemShortcut);
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 99e15ba..115a6e6 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -98,7 +98,7 @@
public abstract class AbstractLauncherUiTest<LAUNCHER_TYPE extends Launcher> {
public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
- public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
+ public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 10;
public static final long DEFAULT_UI_TIMEOUT = TestUtil.DEFAULT_UI_TIMEOUT;
private static final String TAG = "AbstractLauncherUiTest";
@@ -548,7 +548,7 @@
public Intent blockingGetIntent() throws InterruptedException {
Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT,
"AbstractLauncherUiTest.blockingGetIntent()");
- latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
+ assertTrue("Timed Out", latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS));
mTargetContext.unregisterReceiver(this);
Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT, mIntent == null
? "AbstractLauncherUiTest.onReceive(): mIntent NULL"
diff --git a/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java b/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
index 3411fc1..e49f2b1 100644
--- a/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
+++ b/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
@@ -69,13 +69,7 @@
private WorkProfileManager mWorkManager;
private Context mContext;
- @Rule public final SetFlagsRule mSetFlagsRule = getFlagsRule();
-
- private SetFlagsRule getFlagsRule() {
- SetFlagsRule flagsRule = new SetFlagsRule();
- flagsRule.initAllFlagsToReleaseConfigDefault();
- return flagsRule;
- }
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Before
public void setUp() {
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index c4e74f2..e5c5c19 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -57,7 +57,7 @@
true));
} catch (Throwable e) {
- FailureWatcher.onError(mTest.mLauncher, description, e);
+ FailureWatcher.onError(mTest.mLauncher, description);
throw e;
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
index 342eedf..4a67600 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
@@ -21,8 +21,9 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.Launcher;
+import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,6 +32,7 @@
@RunWith(AndroidJUnit4.class)
public class TaplTestsLauncher3Test extends AbstractLauncherUiTest<Launcher> {
+ @KeepRecordOnSuccess
@ScreenRecord // b/322823478
@Test
public void testDevicePressMenu() throws Exception {
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index e08d37c..69b42cb 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -45,6 +45,7 @@
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.TestStabilityRule.Stability;
@@ -75,7 +76,6 @@
String output =
mDevice.executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");
- // b/203817455
updateWorkProfileSetupSuccessful("pm create-user", output);
String[] tokens = output.split("\\s+");
@@ -196,6 +196,7 @@
}
+ @KeepRecordOnSuccess
@ScreenRecord // b/322823478
@Test
public void testEdu() {
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 7845dec..9dbd866 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -86,7 +86,6 @@
* A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it.
* Custom shortcuts are replaced by deep shortcuts after api 25.
*/
- @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
@Test
@PortraitLandscape
public void testDragCustomShortcut() throws Throwable {
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index 2ce8eef..a672c01 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -20,6 +20,8 @@
import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.MESSAGES_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
+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.assertNotNull;
@@ -38,6 +40,7 @@
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.ScreenRecordRule;
+import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.After;
import org.junit.Before;
@@ -242,6 +245,7 @@
}
@ScreenRecordRule.ScreenRecord // b/329935119
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/329935119
@Test
@PortraitLandscape
public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() {
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
index 9afde0d..490cff2 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
@@ -29,6 +29,7 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import org.junit.After;
import org.junit.Before;
@@ -67,6 +68,7 @@
* move between workspaces. After, make sure we can launch an app from the Workspace.
* @throws Exception if we can't set the defaults icons that will appear at the beginning.
*/
+ @ScreenRecord // b/331261431
@Test
public void testWorkspace() throws Exception {
// Set workspace that includes the chrome Activity app icon on the hotseat.
diff --git a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
index 706ab27..273f0c4 100644
--- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -31,6 +31,7 @@
import androidx.test.filters.SmallTest
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
import com.android.launcher3.util.DisplayController.CHANGE_DENSITY
import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
import com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING
@@ -45,6 +46,7 @@
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
@@ -93,6 +95,7 @@
whenever(context.getObject(eq(WindowManagerProxy.INSTANCE))).thenReturn(windowManagerProxy)
whenever(context.getObject(eq(LauncherPrefs.INSTANCE))).thenReturn(launcherPrefs)
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
+ whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(true)
// Mock WindowManagerProxy
val displayInfo = CachedDisplayInfo(Point(width, height), Surface.ROTATION_0)
@@ -123,6 +126,7 @@
whenever(displayManager.getDisplay(any())).thenReturn(display)
// Mock resources
+ doReturn(context).whenever(context).applicationContext
whenever(resources.configuration).thenReturn(configuration)
whenever(context.resources).thenReturn(resources)
@@ -168,4 +172,13 @@
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
+
+ @Test
+ @UiThreadTest
+ fun testTaskbarPinningChangeInDesktopMode() {
+ whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(false)
+ displayController.handleInfoChange(display)
+ verify(displayInfoChangeListener)
+ .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
+ }
}
diff --git a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
index d1da5f4..b5e797e 100644
--- a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
+++ b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
@@ -34,6 +34,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Rule;
@@ -63,6 +64,8 @@
mContext = mock(Context.class);
mLauncherApps = mock(LauncherApps.class);
when(mContext.getSystemService(eq(LauncherApps.class))).thenReturn(mLauncherApps);
+ when(mContext.getResources()).thenReturn(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getResources());
mPackageManagerHelper = new PackageManagerHelper(mContext);
}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 7fba33e..7bdc040 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -30,6 +30,8 @@
public class FailureWatcher extends TestWatcher {
private static final String TAG = "FailureWatcher";
private static boolean sSavedBugreport = false;
+ private static Description sDescriptionForLastSavedArtifacts;
+
private final LauncherInstrumentation mLauncher;
@NonNull
private final Supplier<ExportedData> mViewCaptureDataSupplier;
@@ -41,6 +43,18 @@
}
@Override
+ protected void starting(Description description) {
+ mLauncher.setOnFailure(() -> onError(mLauncher, description, mViewCaptureDataSupplier));
+ super.starting(description);
+ }
+
+ @Override
+ protected void finished(Description description) {
+ super.finished(description);
+ mLauncher.setOnFailure(null);
+ }
+
+ @Override
protected void succeeded(Description description) {
super.succeeded(description);
AbstractLauncherUiTest.checkDetectedLeaks(mLauncher);
@@ -70,7 +84,7 @@
@Override
protected void failed(Throwable e, Description description) {
- onError(mLauncher, description, e, mViewCaptureDataSupplier);
+ onError(mLauncher, description, mViewCaptureDataSupplier);
}
static File diagFile(Description description, String prefix, String ext) {
@@ -79,13 +93,18 @@
+ description.getMethodName() + "." + ext);
}
- public static void onError(LauncherInstrumentation launcher, Description description,
- Throwable e) {
- onError(launcher, description, e, null);
+ /** Action executed when an error condition is expected. Saves artifacts. */
+ public static void onError(LauncherInstrumentation launcher, Description description) {
+ onError(launcher, description, null);
}
private static void onError(LauncherInstrumentation launcher, Description description,
- Throwable e, @Nullable Supplier<ExportedData> viewCaptureDataSupplier) {
+ @Nullable Supplier<ExportedData> viewCaptureDataSupplier) {
+ if (description.equals(sDescriptionForLastSavedArtifacts)) {
+ // This test has already saved its artifacts.
+ return;
+ }
+ sDescriptionForLastSavedArtifacts = description;
final File sceenshot = diagFile(description, "TestScreenshot", "png");
final File hierarchy = diagFile(description, "Hierarchy", "zip");
@@ -114,7 +133,7 @@
Log.e(TAG, "Failed test " + description.getMethodName()
+ ",\nscreenshot will be saved to " + sceenshot
+ ",\nUI dump at: " + hierarchy
- + " (use go/web-hv to open the dump file)", e);
+ + " (use go/web-hv to open the dump file)");
final UiDevice device = launcher.getDevice();
device.takeScreenshot(sceenshot);
diff --git a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
index 7a5cf2c..ff96afb 100644
--- a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
@@ -49,6 +49,9 @@
return base;
}
+ final Boolean keepRecordOnSuccess = description.getAnnotation(KeepRecordOnSuccess.class)
+ != null;
+
return new Statement() {
@Override
public void evaluate() throws Throwable {
@@ -70,7 +73,7 @@
device.executeShellCommand("kill -INT " + screenRecordPid);
Log.e(TAG, "Screenrecord captured at: " + outputFile);
output.close();
- if (success) {
+ if (success && !keepRecordOnSuccess) {
automation.executeShellCommand("rm " + outputFile);
}
}
@@ -85,4 +88,14 @@
@Target(ElementType.METHOD)
public @interface ScreenRecord {
}
+
+
+ /**
+ * Interface to indicate that we should keep the screen record even if the test succeeds, use
+ * sparingly since it uses a lof of memory.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public @interface KeepRecordOnSuccess {
+ }
}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 8fc4481..d4e061a 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -31,6 +31,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.os.UserHandle;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -79,7 +80,8 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = new ActivityContextWrapper(getApplicationContext());
+ mContext = new ActivityContextWrapper(new ContextThemeWrapper(getApplicationContext(),
+ R.style.WidgetContainerTheme));
mTestProfile = new InvariantDeviceProfile();
mTestProfile.numRows = 5;
mTestProfile.numColumns = 5;
diff --git a/tests/src_deviceless/com/android/launcher3/util/RobolectricDeviceRunner.kt b/tests/src_deviceless/com/android/launcher3/util/RobolectricDeviceRunner.kt
new file mode 100644
index 0000000..dc6d716
--- /dev/null
+++ b/tests/src_deviceless/com/android/launcher3/util/RobolectricDeviceRunner.kt
@@ -0,0 +1,107 @@
+/*
+ * 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 androidx.test.annotation.UiThreadTest
+import androidx.test.platform.app.InstrumentationRegistry
+import java.lang.reflect.Method
+import java.util.concurrent.atomic.AtomicReference
+import org.junit.runners.model.FrameworkMethod
+import org.junit.runners.model.Statement
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.internal.bytecode.Sandbox
+import org.robolectric.util.ReflectionHelpers
+import org.robolectric.util.ReflectionHelpers.ClassParameter
+
+/** Runner which emulates the provided display before running the actual test */
+class RobolectricDeviceRunner(testClass: Class<*>?, private val deviceName: String?) :
+ RobolectricTestRunner(testClass) {
+
+ private val nameSuffix = deviceName?.let { "-$it" } ?: ""
+
+ override fun getName() = super.getName() + nameSuffix
+
+ override fun testName(method: FrameworkMethod) = super.testName(method) + nameSuffix
+
+ @Throws(Throwable::class)
+ override fun beforeTest(sandbox: Sandbox, method: FrameworkMethod, bootstrappedMethod: Method) {
+ super.beforeTest(sandbox, method, bootstrappedMethod)
+
+ deviceName ?: return
+
+ val emulator =
+ try {
+ ReflectionHelpers.loadClass(
+ bootstrappedMethod.declaringClass.classLoader,
+ DEVICE_EMULATOR
+ )
+ } catch (e: Exception) {
+ // Ignore, if the device emulator is not present
+ return
+ }
+ ReflectionHelpers.callStaticMethod<Any>(
+ emulator,
+ "updateDevice",
+ ClassParameter.from(String::class.java, deviceName)
+ )
+ }
+
+ override fun getHelperTestRunner(clazz: Class<*>) = MyHelperTestRunner(clazz)
+
+ class MyHelperTestRunner(clazz: Class<*>) : HelperTestRunner(clazz) {
+
+ override fun methodBlock(method: FrameworkMethod): Statement =
+ // this needs to be run in the test classLoader
+ ReflectionHelpers.callStaticMethod(
+ method.declaringClass.classLoader,
+ RobolectricDeviceRunner::class.qualifiedName,
+ "wrapUiThreadMethod",
+ ClassParameter.from(FrameworkMethod::class.java, method),
+ ClassParameter.from(Statement::class.java, super.methodBlock(method))
+ )
+ }
+
+ private class UiThreadStatement(val base: Statement) : Statement() {
+
+ override fun evaluate() {
+ val exceptionRef = AtomicReference<Throwable>()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ try {
+ base.evaluate()
+ } catch (throwable: Throwable) {
+ exceptionRef.set(throwable)
+ }
+ }
+ exceptionRef.get()?.let { throw it }
+ }
+ }
+
+ companion object {
+
+ private const val DEVICE_EMULATOR = "com.android.launcher3.util.RoboDeviceEmulator"
+
+ @JvmStatic
+ fun wrapUiThreadMethod(method: FrameworkMethod, base: Statement): Statement =
+ if (
+ method.method.isAnnotationPresent(UiThreadTest::class.java) ||
+ method.declaringClass.isAnnotationPresent(UiThreadTest::class.java)
+ ) {
+ UiThreadStatement(base)
+ } else {
+ base
+ }
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 245ec09..71cd19d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -58,6 +58,7 @@
private static final String FAST_SCROLLER_RES_ID = "fast_scroller";
private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
+ private static final String UNLOCK_BUTTON_VIEW_RES_ID = "ps_lock_unlock_button";
private final int mHeight;
private final int mIconHeight;
@@ -291,6 +292,10 @@
return mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view");
}
+ protected UiObject2 getAllAppsHeader(UiObject2 allAppsContainer) {
+ return mLauncher.waitForObjectInContainer(allAppsContainer, "all_apps_header");
+ }
+
protected UiObject2 getSearchBox(UiObject2 allAppsContainer) {
return mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
}
@@ -416,12 +421,41 @@
}
}
+ /** Returns PredictionRow if present in view. */
+ @NonNull
+ public PredictionRow getPredictionRowView() {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 allAppsHeader = getAllAppsHeader(allAppsContainer);
+ return new PredictionRow(mLauncher, allAppsHeader);
+ }
+
/** Returns PrivateSpaceContainer if present in view. */
@NonNull
public PrivateSpaceContainer getPrivateSpaceUnlockedView() {
final UiObject2 allAppsContainer = verifyActiveContainer();
final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
- return new PrivateSpaceContainer(mLauncher, appListRecycler);
+ return new PrivateSpaceContainer(mLauncher, appListRecycler, this, true);
+ }
+
+ /** Returns PrivateSpaceContainer in locked state, if present in view. */
+ @NonNull
+ public PrivateSpaceContainer getPrivateSpaceLockedView() {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
+ return new PrivateSpaceContainer(mLauncher, appListRecycler, this, false);
+ }
+
+ /**
+ * Toggles Lock/Unlock of Private Space, changing the All Apps Ui.
+ */
+ public void togglePrivateSpace() {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
+ UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(appListRecycler,
+ UNLOCK_BUTTON_VIEW_RES_ID);
+ mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button");
+ mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable());
+ unLockButtonView.click();
}
protected abstract void verifyVisibleContainerOnDismiss();
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 68829e0..2e3944d 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -359,6 +359,21 @@
}
/**
+ * Gets Overview Actions specific to grouped tasks.
+ *
+ * @return The Overview group actions bar
+ */
+ @NonNull
+ public OverviewActions getOverviewGroupActions() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get overview group actions")) {
+ verifyActiveContainer();
+ UiObject2 groupActions = mLauncher.waitForOverviewObject("group_action_buttons");
+ return new OverviewActions(groupActions, mLauncher);
+ }
+ }
+
+ /**
* Returns if clear all button is visible.
*/
public boolean isClearAllVisible() {
@@ -449,10 +464,18 @@
private void verifyActionsViewVisibility() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to assert overview actions view visibility")) {
+ boolean isTablet = mLauncher.isTablet();
+ OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
+
if (isActionsViewVisible()) {
- mLauncher.waitForOverviewObject("action_buttons");
+ if (task.isTaskSplit()) {
+ mLauncher.waitForOverviewObject("group_action_buttons");
+ } else {
+ mLauncher.waitForOverviewObject("action_buttons");
+ }
} else {
mLauncher.waitUntilOverviewObjectGone("action_buttons");
+ mLauncher.waitUntilOverviewObjectGone("group_action_buttons");
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 3f96999..200f2ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -24,13 +24,11 @@
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
-import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -141,8 +139,6 @@
return new Taskbar(mLauncher);
} finally {
- Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "swipeUpToUnstashTaskbar: completed gesture");
mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 0a52955..68b0a36 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -31,10 +31,8 @@
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_GET_SPLIT_SELECTION_ACTIVE;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_NUM_ALL_APPS_COLUMNS;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.app.ActivityManager;
import android.app.Instrumentation;
@@ -110,7 +108,7 @@
public final class LauncherInstrumentation {
private static final String TAG = "Tapl";
- private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
+ private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 5;
private static final int GESTURE_STEP_MS = 16;
static final Pattern EVENT_PILFER_POINTERS = Pattern.compile("pilferPointers");
@@ -206,6 +204,7 @@
private Runnable mTestAnomalyChecker;
private boolean mCheckEventsForSuccessfulGestures = false;
+ private Runnable mOnFailure;
private Runnable mOnLauncherCrashed;
private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
@@ -344,6 +343,11 @@
mCheckEventsForSuccessfulGestures = true;
}
+ /** Sets a runnable that will be invoked upon assertion failures. */
+ public void setOnFailure(Runnable onFailure) {
+ mOnFailure = onFailure;
+ }
+
public void setOnLauncherCrashed(Runnable onLauncherCrashed) {
mOnLauncherCrashed = onLauncherCrashed;
}
@@ -625,6 +629,7 @@
final String systemAnomalyMessage =
getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
if (systemAnomalyMessage != null) {
+ if (mOnFailure != null) mOnFailure.run();
Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
"http://go/tapl : Tests are broken by a non-Launcher system error: "
+ systemAnomalyMessage, false)));
@@ -744,6 +749,7 @@
void fail(String message) {
checkForAnomaly();
+ if (mOnFailure != null) mOnFailure.run();
Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
"http://go/tapl test failure: " + message + ";\nContext: " + getContextDescription()
+ "; now visible state is " + getVisibleStateMessage(), true)));
@@ -768,7 +774,7 @@
fail(message + ". " + "Actual: " + actual);
}
- private void assertEquals(String message, int expected, int actual) {
+ void assertEquals(String message, int expected, int actual) {
if (expected != actual) {
fail(message + " expected: " + expected + " but was: " + actual);
}
@@ -2400,13 +2406,9 @@
}
if (mEventChecker != null) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "eventsCheck: mEventChecker exists");
mEventChecker = null;
if (mCheckEventsForSuccessfulGestures) {
final String message = eventChecker.verify(WAIT_TIME_MS, true);
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "mCheckEventsForSuccessfulGestures = true | eventsCheck: message="
- + message);
if (message != null) {
dumpDiagnostics(message);
checkForAnomaly();
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 70d63bd..672c6e0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -18,8 +18,6 @@
import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_MAIN;
import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_PILFER;
import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_TIS;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.os.SystemClock;
@@ -90,7 +88,6 @@
}
String verify(long waitForExpectedCountMs, boolean successfulGesture) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "LogEventChecker.java - verify");
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
if (actualEvents == null) return "null event sequences because launcher likely died";
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 99da5c3..6f420af 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -19,10 +19,8 @@
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.DEFAULT;
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT;
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import android.graphics.Rect;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -222,7 +220,6 @@
return new LaunchedAppState(mLauncher);
}
} else {
- Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTaskAnimated");
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
return new LaunchedAppState(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/PredictionRow.java b/tests/tapl/com/android/launcher3/tapl/PredictionRow.java
new file mode 100644
index 0000000..11f71fd
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/PredictionRow.java
@@ -0,0 +1,72 @@
+/*
+ * 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.tapl;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+/** View containing prediction app icons */
+public class PredictionRow {
+
+ private static final String PREDICTION_ROW_ID = "prediction_row";
+ private static final String PREDICTION_APP_ID = "icon";
+ private final LauncherInstrumentation mLauncher;
+ private final UiObject2 mAllAppsHeader;
+ private final UiObject2 mPredictionRow;
+
+ PredictionRow(LauncherInstrumentation launcherInstrumentation,
+ UiObject2 allAppsHeader) {
+ mLauncher = launcherInstrumentation;
+ mAllAppsHeader = allAppsHeader;
+ mPredictionRow = mLauncher.waitForObjectInContainer(mAllAppsHeader,
+ PREDICTION_ROW_ID);
+ verifyAppsPresentInsidePredictionRow();
+ verifyPredictionRowAppsCount();
+ }
+
+ /** Verify that one app is present in prediction row view. */
+ private void verifyAppsPresentInsidePredictionRow() {
+ mLauncher.waitForObjectInContainer(mPredictionRow,
+ PREDICTION_APP_ID);
+ }
+
+ /** Verify that prediction row apps count is same as launcher apps column count. */
+ private void verifyPredictionRowAppsCount() {
+ mLauncher.assertEquals("PredictionRow app count mismatch", mLauncher.getNumAllAppsColumns(),
+ getPredictionRowAppsCount());
+ }
+
+ /**
+ * Returns an app icon found in the prediction row. This fails if any icon is not
+ * found.
+ */
+ @NonNull
+ private HomeAppIcon getAnyAppIcon() {
+ return new AllAppsAppIcon(mLauncher,
+ mPredictionRow.findObject(AppIcon.getAnyAppIconSelector()));
+ }
+
+ /**
+ * Returns the size of prediction row apps count.
+ */
+ private int getPredictionRowAppsCount() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get all prediction row icons")) {
+ return mPredictionRow.findObjects(AppIcon.getAnyAppIconSelector()).size();
+ }
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
index 2c16e01..a2814f0 100644
--- a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
@@ -16,6 +16,8 @@
package com.android.launcher3.tapl;
+import android.graphics.Point;
+
import androidx.test.uiautomator.UiObject2;
/**
@@ -23,20 +25,30 @@
*/
public class PrivateSpaceContainer {
private static final String PS_HEADER_RES_ID = "ps_header_layout";
- private static final String INSTALL_APP_TITLE = "Install apps";
+ private static final String INSTALL_APP_TITLE = "Install";
private static final String DIVIDER_RES_ID = "private_space_divider";
private final LauncherInstrumentation mLauncher;
private final UiObject2 mAppListRecycler;
+ private final AllApps mAppList;
+ private final boolean mPrivateSpaceEnabled;
PrivateSpaceContainer(LauncherInstrumentation launcherInstrumentation,
- UiObject2 appListRecycler) {
+ UiObject2 appListRecycler, AllApps appList, boolean privateSpaceEnabled) {
mLauncher = launcherInstrumentation;
mAppListRecycler = appListRecycler;
+ mAppList = appList;
+ mPrivateSpaceEnabled = privateSpaceEnabled;
- verifyHeaderIsPresent();
- verifyInstallAppButtonIsPresent();
- verifyDividerIsPresent();
+ if (mPrivateSpaceEnabled) {
+ verifyHeaderIsPresent();
+ verifyInstallAppButtonIsPresent();
+ verifyDividerIsPresent();
+ } else {
+ verifyHeaderIsPresent();
+ verifyInstallAppButtonIsNotPresent();
+ verifyDividerIsNotPresent();
+ }
}
// Assert PS Header is in view.
@@ -44,17 +56,39 @@
private void verifyHeaderIsPresent() {
final UiObject2 psHeader = mLauncher.waitForObjectInContainer(mAppListRecycler,
PS_HEADER_RES_ID);
- new PrivateSpaceHeader(mLauncher, psHeader, true);
+ new PrivateSpaceHeader(mLauncher, psHeader, mPrivateSpaceEnabled);
}
// Assert Install App Item is present in view.
private void verifyInstallAppButtonIsPresent() {
- mLauncher.getAllApps().getAppIcon(INSTALL_APP_TITLE);
+ mAppList.getAppIcon(INSTALL_APP_TITLE);
+ }
+
+ // Assert Install App Item is not present in view.
+ private void verifyInstallAppButtonIsNotPresent() {
+ mLauncher.waitUntilLauncherObjectGone(DIVIDER_RES_ID);
}
// Assert Sys App Divider is present in view.
private void verifyDividerIsPresent() {
mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID);
}
-}
+
+ // Assert Sys App Divider is not present in view.
+ private void verifyDividerIsNotPresent() {
+ mLauncher.waitUntilLauncherObjectGone(DIVIDER_RES_ID);
+ }
+
+ /**
+ * Verifies that a user installed app is present above the divider.
+ */
+ public void verifyInstalledAppIsPresent(String appName) {
+ AppIcon appIcon = mAppList.getAppIcon(appName);
+ final Point iconCenter = appIcon.mObject.getVisibleCenter();
+ UiObject2 divider = mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID);
+ final Point dividerCenter = divider.getVisibleCenter();
+ mLauncher.assertTrue("Installed App: " + appName + " is not above the divider",
+ iconCenter.y < dividerCenter.y);
+ }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
index 3a7f038..cc64aae 100644
--- a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
@@ -45,7 +45,7 @@
if (mPrivateSpaceEnabled) {
verifyUnlockedState();
} else {
- mLauncher.fail("Private Space found in non enabled state");
+ verifyLockedState();
}
}
@@ -74,4 +74,23 @@
mLauncher.assertEquals("PS lock text is incorrect", "Lock", lockText.getText());
}
+
+ /** Verify Locked State elements in Private Space Header */
+ private void verifyLockedState() {
+ UiObject2 headerText = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+ PS_HEADER_TEXT_RES_ID);
+ mLauncher.assertEquals("PS Header Text is incorrect ",
+ "Private", headerText.getText());
+
+ UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+ UNLOCK_BUTTON_VIEW_RES_ID);
+ mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button");
+ mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable());
+
+ mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+ LOCK_ICON_RES_ID);
+
+ mLauncher.waitUntilLauncherObjectGone(SETTINGS_BUTTON_RES_ID);
+ mLauncher.waitUntilLauncherObjectGone(LOCK_TEXT_RES_ID);
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index 8d3a631..4be46ab 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import android.text.TextUtils;
import android.widget.TextView;
import androidx.test.uiautomator.By;
@@ -117,4 +118,28 @@
public SearchResultFromQsb getSearchResultForInput() {
return this;
}
+
+ /** Verify a tile is present by checking its title and subtitle. */
+ public void verifyTileIsPresent(String title, String subtitle) {
+ ArrayList<UiObject2> searchResults =
+ new ArrayList<>(mLauncher.waitForObjectsInContainer(
+ mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),
+ By.clazz(TextView.class)));
+ boolean foundTitle = false;
+ boolean foundSubtitle = false;
+ for (UiObject2 uiObject: searchResults) {
+ String currentString = uiObject.getText();
+ if (TextUtils.equals(currentString, title)) {
+ foundTitle = true;
+ } else if (TextUtils.equals(currentString, subtitle)) {
+ foundSubtitle = true;
+ }
+ }
+ if (!foundTitle) {
+ mLauncher.fail("Tile not found for title: " + title);
+ }
+ if (!foundSubtitle) {
+ mLauncher.fail("Tile not found for subtitle: " + subtitle);
+ }
+ }
}