Merge "Disable launcher focus outline animation" into main
diff --git a/Android.bp b/Android.bp
index eed67f5..13a926b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -141,6 +141,7 @@
static_libs: [
"LauncherPluginLib",
"launcher_quickstep_log_protos_lite",
+ "android.os.flags-aconfig-java",
"androidx-constraintlayout_constraintlayout",
"androidx.recyclerview_recyclerview",
"androidx.dynamicanimation_dynamicanimation",
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index a31ee80..edbea88 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -52,18 +52,18 @@
name in the permissions. eq com.mypackage.permission.READ_SETTINGS
-->
<permission
- android:name="${packageName}.permission.READ_SETTINGS"
+ android:name="${applicationId}.permission.READ_SETTINGS"
android:protectionLevel="signatureOrSystem"
android:label="@string/permlab_read_settings"
android:description="@string/permdesc_read_settings"/>
<permission
- android:name="${packageName}.permission.WRITE_SETTINGS"
+ android:name="${applicationId}.permission.WRITE_SETTINGS"
android:protectionLevel="signatureOrSystem"
android:label="@string/permlab_write_settings"
android:description="@string/permdesc_write_settings"/>
- <uses-permission android:name="${packageName}.permission.READ_SETTINGS" />
- <uses-permission android:name="${packageName}.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="${applicationId}.permission.READ_SETTINGS" />
+ <uses-permission android:name="${applicationId}.permission.WRITE_SETTINGS" />
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -126,10 +126,10 @@
-->
<provider
android:name="com.android.launcher3.LauncherProvider"
- android:authorities="${packageName}.settings"
+ android:authorities="${applicationId}.settings"
android:exported="true"
- android:writePermission="${packageName}.permission.WRITE_SETTINGS"
- android:readPermission="${packageName}.permission.READ_SETTINGS" />
+ android:writePermission="${applicationId}.permission.WRITE_SETTINGS"
+ android:readPermission="${applicationId}.permission.READ_SETTINGS" />
<!--
The content provider for exposing various launcher grid options.
@@ -137,7 +137,7 @@
-->
<provider
android:name="com.android.launcher3.graphics.GridCustomizationsProvider"
- android:authorities="${packageName}.grid_control"
+ android:authorities="${applicationId}.grid_control"
android:exported="true" />
<!--
@@ -157,7 +157,7 @@
<provider
android:name="com.android.launcher3.testing.TestInformationProvider"
- android:authorities="${packageName}.TestInfo"
+ android:authorities="${applicationId}.TestInfo"
android:readPermission="android.permission.WRITE_SECURE_SETTINGS"
android:writePermission="android.permission.WRITE_SECURE_SETTINGS"
android:exported="true"
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 6b07bb6..163fc17 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,10 @@
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"
+}
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/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 2d2fb97..bf198b6 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -50,7 +50,7 @@
<uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL" />
<!-- Permission required to start a WidgetPickerActivity. -->
- <permission android:name="${packageName}.permission.START_WIDGET_PICKER_ACTIVITY"
+ <permission android:name="${applicationId}.permission.START_WIDGET_PICKER_ACTIVITY"
android:protectionLevel="signature|privileged" />
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -88,7 +88,7 @@
<!-- Content provider to settings search. The autority should be same as the packageName -->
<provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
- android:authorities="${packageName}"
+ android:authorities="${applicationId}"
android:grantUriPermissions="true"
android:multiprocess="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES"
@@ -100,7 +100,7 @@
<!-- FileProvider used for sharing images. -->
<provider android:name="androidx.core.content.FileProvider"
- android:authorities="${packageName}.overview.fileprovider"
+ android:authorities="${applicationId}.overview.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
similarity index 97%
rename from quickstep/res/layout/keyboard_quick_switch_overview.xml
rename to quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
index 30ca32d..e48794e 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
@@ -40,7 +40,6 @@
android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
android:layout_marginBottom="8dp"
- android:src="@drawable/view_carousel"
android:tint="?androidprv:attr/materialColorOnSurface"
app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 9d599c9..9f648a7 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,7 +28,7 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <com.android.quickstep.views.TaskThumbnailView
+ <com.android.quickstep.views.TaskThumbnailViewDeprecated
android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 3cafcfd..36d7f86 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -42,7 +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
+ <com.android.quickstep.views.TaskThumbnailViewDeprecated
android:id="@+id/snapshot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index e91e773..ec657bd 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,12 +33,12 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <com.android.quickstep.views.TaskThumbnailView
+ <com.android.quickstep.views.TaskThumbnailViewDeprecated
android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- <com.android.quickstep.views.TaskThumbnailView
+ <com.android.quickstep.views.TaskThumbnailViewDeprecated
android:id="@+id/bottomright_snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
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 e1f52e7..ab1dd78 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Rekenaar"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..e7fe0fa 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..e98fc2f 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 72482ff..9b75dad 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 68fcb3c..25a0fc8 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</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">"Son elementlər yoxdur"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 6fb8f01..aaa7d8c 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/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">"Slobodni oblik"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računar"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..4d65ecd 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..bf42a23 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..89a5e76 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..059c14c 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 a13e943..f2118eb 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format lliure"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinador"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuració d\'ús d\'aplicacions"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Esborra-ho tot"</string>
@@ -119,7 +118,7 @@
<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 de Google<xliff:g id="END_TOS_LINK"></a></xliff:g>."</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_edu_close" msgid="887022990168191073">"Tanca"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Fet"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Inici"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..0771ace 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..a805762 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..b1ce2d5 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 30c4dc8..030d834 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..a083fa4 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..cadf7ee 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -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..a083fa4 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..a083fa4 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..7f1aa13 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -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..0a92029 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..0d1ebe0 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..77529cb 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..8a504ec 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..8141045 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..18331a2 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 33536b7..467a72a 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur de bureau"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 bf89f83..20b9bab 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..71ebcf7 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..cb3c03f 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..ebe7d89 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..a8875ad 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..4650f4d 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..04049a9 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..833a568 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..5d3693d 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..a9391f6 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..7514ba1 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..0cc9f89 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 b4eb026..d24a698 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 a8bbdf5..5073a3f 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,7 +117,7 @@
<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_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_edu_close" msgid="887022990168191073">"Жабу"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Дайын"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 3b7180c..0d9aa52 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..e4ff655 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..90486bd 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..00573c3 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 211e9ed..c2ec34f 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..a4ca187 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..7fef880 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..832bd74 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..6432438 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..4ab619e 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..cae868d 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 87c6e24..92f6a64 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk 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">"Tiada item terbaharu"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..f694c39 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..54f2596 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 acfa2ce..401e13b 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index c288868..e2e0dbe 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 a67cff9..d05fe1e 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>
@@ -128,7 +127,7 @@
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME ସ୍ୱିଚର"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"ବର୍ତ୍ତମାନର"</string>
<string name="taskbar_button_notifications" msgid="7471740351507357318">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
- <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କ୍ୱିକ ସେଟିଂସ"</string>
+ <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କୁଇକ ସେଟିଂସ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ଟାସ୍କବାର"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ଟାସ୍କବାର ଦେଖାଯାଇଛି"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ଟାସ୍କବାର ଲୁଚାଯାଇଛି"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..3256033 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..4792733 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -138,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 202813b..4f96a38 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/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">"Definições de utilização de aplicações"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..2530361 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..0d54d0d 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..41e0f35 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 65dde9d..f90dd28 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..3b5639c 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..6714240 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..f67efb6 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 0164d67..5ad5c1f 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..67f7928 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 9d925a5..8f4d3fd 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Kompyuta ya mezani"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..5a4630e 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 5f1feff..ceee6e5 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 ea6a285..71f9950 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..3c3acc1 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..45d2fc4 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..4838552 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..ee96e5c 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..41e6d24 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..709fb10 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..d30fdfa 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 c006c59..d8e698c 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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 e793df6..98465a6 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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..bbb6631 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>
@@ -139,6 +138,8 @@
<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>
+ <!-- no translation found for quick_switch_desktop (4834587349322698616) -->
+ <skip />
<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/config.xml b/quickstep/res/values/config.xml
index 28cdb99..b3502db 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -35,6 +35,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 69e07f2..dbf075c 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -403,7 +403,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,18 +420,26 @@
<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>
<dimen name="bubblebar_drag_elevation">2dp</dimen>
<dimen name="bubblebar_hotseat_adjustment_threshold">90dp</dimen>
- <dimen name="bubblebar_icon_size">50dp</dimen>
+ <dimen name="bubblebar_icon_size_small">32dp</dimen>
+ <dimen name="bubblebar_icon_size">36dp</dimen>
<dimen name="bubblebar_badge_size">24dp</dimen>
<dimen name="bubblebar_icon_overlap">12dp</dimen>
- <dimen name="bubblebar_overflow_inset">24dp</dimen>
- <dimen name="bubblebar_icon_spacing">3dp</dimen>
+ <dimen name="bubblebar_overflow_inset">16dp</dimen>
+ <dimen name="bubblebar_icon_spacing">6dp</dimen>
+ <dimen name="bubblebar_icon_spacing_large">8dp</dimen>
+ <dimen name="bubblebar_expanded_icon_spacing">12dp</dimen>
<dimen name="bubblebar_icon_elevation">1dp</dimen>
<!-- Bubble bar dismiss view -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 71855eb..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] -->
@@ -324,6 +324,12 @@
other{Show # more apps.}
}</string>
+ <!-- Label for quick switch tile showing how many apps are available in desktop mode [CHAR LIMIT=NONE] -->
+ <string name="quick_switch_desktop">{count, plural,
+ =1{Show # desktop app.}
+ other{Show # desktop apps.}
+ }</string>
+
<!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
<string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index fb14f9e..65a49bd 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -326,8 +326,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();
}
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/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 74376c8..5ac5761 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -37,6 +37,9 @@
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 +51,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 +131,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 +154,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 +198,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 +222,15 @@
}
}
+ private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible);
+ }
+ for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
+ listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
+ }
+ }
+
/**
* TODO: b/333533253 - Remove after flag rollout
*/
@@ -359,4 +394,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/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
new file mode 100644
index 0000000..f665e21
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
@@ -0,0 +1,139 @@
+/*
+ * 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,
+ private val desktopVisibilityController: DesktopVisibilityController?,
+) : TaskbarRecentAppsController() {
+
+ private var apps: Array<AppInfo>? = null
+ private var allRunningDesktopAppInfos: List<AppInfo>? = null
+ private var runningDesktopAppInfosExceptHotseatItems: List<ItemInfo>? = null
+
+ 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>? {
+ val actualHotseatItems = hotseatItems ?: return super.updateHotseatItemInfos(null)
+ if (!isInDesktopMode) {
+ Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode")
+ return hotseatItems
+ }
+ val newHotseatItemInfos =
+ actualHotseatItems
+ // Ignore predicted apps - we show running apps instead
+ .filter { itemInfo -> !itemInfo.isPredictedItem }
+ .toMutableList()
+ val runningDesktopAppInfos =
+ runningDesktopAppInfosExceptHotseatItems ?: return newHotseatItemInfos.toTypedArray()
+ newHotseatItemInfos.addAll(runningDesktopAppInfos)
+ return newHotseatItemInfos.toTypedArray()
+ }
+
+ @VisibleForTesting
+ public override fun updateRunningApps(hotseatItems: SparseArray<ItemInfo>?) {
+ if (!isInDesktopMode) {
+ Log.d(TAG, "updateRunningApps: not in Desktop Mode")
+ mControllers.taskbarViewController.commitRunningAppsToUI()
+ return
+ }
+ val allRunningDesktopAppInfos = getRunningDesktopAppInfos()
+ this.allRunningDesktopAppInfos = allRunningDesktopAppInfos
+ runningDesktopAppInfosExceptHotseatItems =
+ hotseatItems?.let {
+ getRunningDesktopAppInfosExceptHotseatApps(allRunningDesktopAppInfos, it.toList())
+ }
+
+ 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/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 584106b..b213203 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -151,20 +151,10 @@
private void processLoadedTasks(ArrayList<GroupTask> tasks) {
// Only store MAX_TASK tasks, from most to least recent
Collections.reverse(tasks);
-
- // Hide all desktop tasks and show them on the hidden tile
- int hiddenDesktopTasks = 0;
- DesktopTask desktopTask = findDesktopTask(tasks);
- if (desktopTask != null) {
- hiddenDesktopTasks = desktopTask.tasks.size();
- tasks = tasks.stream()
- .filter(t -> !(t instanceof DesktopTask))
- .collect(Collectors.toCollection(ArrayList<GroupTask>::new));
- }
mTasks = tasks.stream()
.limit(MAX_TASKS)
.collect(Collectors.toList());
- mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS) + hiddenDesktopTasks;
+ mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
}
private void processLoadedTasksOnDesktop(ArrayList<GroupTask> tasks) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index a5383f5..5d47212 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -36,11 +36,14 @@
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import android.widget.HorizontalScrollView;
+import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.content.res.ResourcesCompat;
import com.android.app.animation.Interpolators;
import com.android.launcher3.R;
@@ -48,6 +51,7 @@
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import java.util.HashMap;
@@ -92,6 +96,7 @@
private HorizontalScrollView mScrollView;
private ConstraintLayout mContent;
+ private int mTaskViewWidth;
private int mTaskViewHeight;
private int mSpacing;
private int mOutlineRadius;
@@ -128,6 +133,8 @@
mContent = findViewById(R.id.content);
Resources resources = getResources();
+ mTaskViewWidth = resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_taskview_width);
mTaskViewHeight = resources.getDimensionPixelSize(
R.dimen.keyboard_quick_switch_taskview_height);
mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
@@ -135,21 +142,18 @@
mIsRtl = Utilities.isRtl(resources);
}
- @NonNull
private KeyboardQuickSwitchTaskView createAndAddTaskView(
int index,
- int width,
boolean isFinalView,
- boolean updateTasks,
+ @LayoutRes int resId,
@NonNull LayoutInflater layoutInflater,
- @Nullable View previousView,
- @NonNull List<GroupTask> groupTasks) {
+ @Nullable View previousView) {
KeyboardQuickSwitchTaskView taskView = (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
- R.layout.keyboard_quick_switch_taskview, mContent, false);
+ resId, mContent, false);
taskView.setId(View.generateViewId());
taskView.setOnClickListener(v -> mViewCallbacks.launchTaskAt(index));
- LayoutParams lp = new LayoutParams(width, mTaskViewHeight);
+ LayoutParams lp = new LayoutParams(mTaskViewWidth, mTaskViewHeight);
// Create a left-to-right ordering of views (or right-to-left in RTL locales)
if (previousView != null) {
lp.startToEnd = previousView.getId();
@@ -167,45 +171,11 @@
lp.horizontalBias = 1f;
}
- GroupTask groupTask = groupTasks.get(index);
- taskView.setThumbnails(
- groupTask.task1,
- groupTask.task2,
- updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
- updateTasks ? mViewCallbacks::updateIconInBackground : null);
-
mContent.addView(taskView, lp);
+
return taskView;
}
- private void createAndAddOverviewButton(
- int width,
- @NonNull LayoutInflater layoutInflater,
- @Nullable View previousView,
- @NonNull String overflowString) {
- KeyboardQuickSwitchTaskView overviewButton =
- (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
- R.layout.keyboard_quick_switch_overview, this, false);
- overviewButton.setOnClickListener(v -> mViewCallbacks.launchTaskAt(MAX_TASKS));
-
- overviewButton.<TextView>findViewById(R.id.text).setText(overflowString);
-
- ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
- width, mTaskViewHeight);
- if (previousView == null) {
- lp.startToStart = PARENT_ID;
- } else {
- lp.endToEnd = PARENT_ID;
- lp.startToEnd = previousView.getId();
- }
- lp.topToTop = PARENT_ID;
- lp.bottomToBottom = PARENT_ID;
- lp.setMarginEnd(mSpacing);
- lp.setMarginStart(mSpacing);
-
- mContent.addView(overviewButton, lp);
- }
-
protected void applyLoadPlan(
@NonNull Context context,
@NonNull List<GroupTask> groupTasks,
@@ -215,32 +185,57 @@
@NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
mViewCallbacks = viewCallbacks;
Resources resources = context.getResources();
- int width = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_taskview_width);
- View previousView = null;
+ Resources.Theme theme = context.getTheme();
+ View previousTaskView = null;
LayoutInflater layoutInflater = LayoutInflater.from(context);
int tasksToDisplay = Math.min(MAX_TASKS, groupTasks.size());
for (int i = 0; i < tasksToDisplay; i++) {
- previousView = createAndAddTaskView(
+ GroupTask groupTask = groupTasks.get(i);
+ KeyboardQuickSwitchTaskView currentTaskView = createAndAddTaskView(
i,
- width,
/* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
- updateTasks,
+ groupTask instanceof DesktopTask
+ ? R.layout.keyboard_quick_switch_textonly_taskview
+ : R.layout.keyboard_quick_switch_taskview,
layoutInflater,
- previousView,
- groupTasks);
+ previousTaskView);
+
+ if (groupTask instanceof DesktopTask desktopTask) {
+ HashMap<String, Integer> args = new HashMap<>();
+ args.put("count", desktopTask.tasks.size());
+
+ currentTaskView.<ImageView>findViewById(R.id.icon).setImageDrawable(
+ ResourcesCompat.getDrawable(resources, R.drawable.ic_desktop, theme));
+ currentTaskView.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+ resources.getString(R.string.quick_switch_desktop),
+ Locale.getDefault()).format(args));
+ } else {
+ currentTaskView.setThumbnails(
+ groupTask.task1,
+ groupTask.task2,
+ updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+ updateTasks ? mViewCallbacks::updateIconInBackground : null);
+ }
+ previousTaskView = currentTaskView;
}
if (numHiddenTasks > 0) {
HashMap<String, Integer> args = new HashMap<>();
args.put("count", numHiddenTasks);
- createAndAddOverviewButton(
- width,
+
+ View overviewButton = createAndAddTaskView(
+ MAX_TASKS,
+ /* isFinalView= */ true,
+ R.layout.keyboard_quick_switch_textonly_taskview,
layoutInflater,
- previousView,
- new MessageFormat(
- resources.getString(R.string.quick_switch_overflow),
- Locale.getDefault()).format(args));
+ previousTaskView);
+
+ overviewButton.<ImageView>findViewById(R.id.icon).setImageDrawable(
+ ResourcesCompat.getDrawable(resources, R.drawable.view_carousel, theme));
+ overviewButton.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+ resources.getString(R.string.quick_switch_overflow),
+ Locale.getDefault()).format(args));
}
mDisplayingRecentTasks = !groupTasks.isEmpty();
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 25a97d4..d6ee92f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -32,6 +32,7 @@
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SlideInRemoteTransition;
import com.android.systemui.shared.recents.model.Task;
@@ -157,7 +158,13 @@
AnimationUtils.loadInterpolator(
context, android.R.interpolator.fast_out_extra_slow_in)),
"SlideInTransition");
- if (mOnDesktop) {
+ if (task instanceof DesktopTask) {
+ UI_HELPER_EXECUTOR.execute(() ->
+ SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
+ .showDesktopApps(
+ mKeyboardQuickSwitchView.getDisplay().getDisplayId(),
+ remoteTransition));
+ } else if (mOnDesktop) {
UI_HELPER_EXECUTOR.execute(() ->
SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
.showDesktopApp(task.task1.key.id));
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 07e9d00..2c2311a 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;
@@ -227,11 +226,7 @@
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
- // TODO(b/308851855): Skip animation for launching split from home, will refine later
- boolean skipAnimForSplit = enableSplitContextually() &&
- mLauncher.areBothSplitAppsConfirmed() &&
- mLauncher.getStateManager().getState() == LauncherState.NORMAL;
- if (skipAnimForSplit || fromInit) {
+ if (fromInit) {
duration = 0;
}
return mTaskbarLauncherStateController.applyState(duration, startAnimation);
@@ -310,8 +305,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;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 49d4afe..1a94424 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -41,6 +41,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;
@@ -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,7 +248,7 @@
mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
- final boolean isDesktopMode = getPackageManager().hasSystemFeature(FEATURE_PC);
+ final boolean isPcMode = getPackageManager().hasSystemFeature(FEATURE_PC);
// If Bubble bar is present, TaskbarControllers depends on it so build it first.
Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
@@ -276,7 +280,7 @@
mControllers = new TaskbarControllers(this,
new TaskbarDragController(this),
buttonController,
- isDesktopMode
+ isPcMode
? new DesktopNavbarButtonsViewController(this, mNavigationBarPanelContext,
navButtonsView)
: new NavbarButtonsViewController(this, mNavigationBarPanelContext,
@@ -301,10 +305,8 @@
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
- isDesktopMode
- ? new DesktopTaskbarRecentAppsController(this)
- : TaskbarRecentAppsController.DEFAULT,
- new TaskbarEduTooltipController(this),
+ createTaskbarRecentAppsController(isPcMode),
+ TaskbarEduTooltipController.newInstance(this),
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this),
bubbleControllersOptional);
@@ -312,6 +314,18 @@
mLauncherPrefs = LauncherPrefs.get(this);
}
+ private TaskbarRecentAppsController createTaskbarRecentAppsController(boolean isPcMode) {
+ if (isPcMode) return new DesktopTaskbarRecentAppsController(this);
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ final boolean showRunningAppsInDesktopMode = enableDesktopWindowingMode()
+ && enableDesktopWindowingTaskbarRunningApps();
+ return showRunningAppsInDesktopMode
+ ? new DesktopTaskbarRunningAppsController(
+ RecentsModel.INSTANCE.get(this),
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController())
+ : TaskbarRecentAppsController.DEFAULT;
+ }
+
/** Updates {@link DeviceProfile} instances for any Taskbar windows. */
public void updateDeviceProfile(DeviceProfile launcherDp) {
applyDeviceProfile(launcherDp);
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/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 14d46d1..6c84f80 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;
@@ -62,6 +67,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 +80,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 +97,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
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 6ceec3e..8e05686 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -207,13 +207,6 @@
}
@Override
- protected void onUserSwipeToDismissProgressChanged() {
- super.onUserSwipeToDismissProgressChanged();
- mAppsView.setClipChildren(!mIsDismissInProgress);
- mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsDismissInProgress);
- }
-
- @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setTranslationShift(mTranslationShift);
@@ -259,12 +252,28 @@
return getPopupContainer().isEventOverView(mAppsView.getVisibleContainerView(), ev);
}
+ /**
+ * In taskbar all apps search mode, we should scale down content inside all apps, rather
+ * than the whole all apps bottom sheet, to indicate we will navigate back within the all apps.
+ */
+ @Override
+ public boolean shouldAnimateContentViewInBackSwipe() {
+ return mAllAppsCallbacks.canHandleSearchBackInvoked();
+ }
+
+ @Override
+ protected void onUserSwipeToDismissProgressChanged() {
+ super.onUserSwipeToDismissProgressChanged();
+ mAppsView.setClipChildren(!mIsDismissInProgress);
+ mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsDismissInProgress);
+ }
+
@Override
public void onBackInvoked() {
if (mAllAppsCallbacks.handleSearchBackInvoked()) {
// We need to scale back taskbar all apps if we navigate back within search inside all
// apps
- animateSwipeToDismissProgressToStart();
+ post(this::animateSwipeToDismissProgressToStart);
} else {
super.onBackInvoked();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index ba4fa45..52f7176 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -143,6 +143,11 @@
}
}
+ /** Check if search session can handle back. This check doesn't perform any action. */
+ boolean canHandleSearchBackInvoked() {
+ return mSearchSessionController.canHandleBackInvoked();
+ }
+
/** Invoked on back press, returning {@code true} if the search session handled it. */
boolean handleSearchBackInvoked() {
return mSearchSessionController.handleBackInvoked();
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
index 3d15fbd..4d0b376 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
@@ -49,6 +49,8 @@
/** Creates a [PreDragCondition] for [view], if it is a search result that requires one. */
open fun createPreDragConditionForSearch(view: View): PreDragCondition? = null
+ open fun canHandleBackInvoked(): Boolean = false
+
open fun handleBackInvoked(): Boolean = false
open fun onAllAppsAnimationPending(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 8eeb055..ec47c4f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -22,22 +22,24 @@
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 val backgroundHeight: Float) : Drawable() {
+class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
private val DARK_THEME_SHADOW_ALPHA = 51f
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,
@@ -127,7 +135,7 @@
val right = if (anchorLeft) width else bounds.width().toFloat()
canvas.drawRoundRect(
left,
- pointerSize,
+ pointerVisibleHeight,
right,
bounds.height().toFloat(),
radius,
@@ -137,10 +145,8 @@
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 = arrowPositionX - pointerWidth / 2f
+ canvas.translate(transX, 0f)
arrowDrawable.draw(canvas)
}
@@ -157,7 +163,7 @@
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
- arrowDrawable.paint.alpha = alpha
+ arrowDrawable.alpha = alpha
}
override fun getAlpha(): Int {
@@ -169,6 +175,10 @@
}
fun setArrowAlpha(alpha: Int) {
- arrowDrawable.paint.alpha = alpha
+ arrowDrawable.alpha = alpha
+ }
+
+ fun setHeight(newHeight: Float) {
+ backgroundHeight = newHeight
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index a2c1b07..981c9f9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -313,8 +313,11 @@
|| (!update.expandedChanged && !mBubbleBarViewController.isExpanded());
final boolean isExpanding = update.expandedChanged && update.expanded;
// don't animate bubbles if this is the initial state because we may be unfolding or
- // enabling gesture nav
- final boolean suppressAnimation = update.initialState;
+ // enabling gesture nav. also suppress animation if the bubble bar is hidden for sysui e.g.
+ // the shade is open, or we're locked.
+ final boolean suppressAnimation =
+ update.initialState || mBubbleBarViewController.isHiddenForSysui();
+
BubbleBarItem previouslySelectedBubble = mSelectedBubble;
BubbleBarBubble bubbleToSelect = null;
if (!update.removedBubbles.isEmpty()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 711ba62..db069d5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -106,10 +106,12 @@
private final Rect mBubbleBarBounds = new Rect();
// The amount the bubbles overlap when they are stacked in the bubble bar
private final float mIconOverlapAmount;
- // The spacing between the bubbles when they are expanded in the bubble bar
- private final float mIconSpacing;
+ // The spacing between the bubbles when bubble bar is expanded
+ private final float mExpandedBarIconsSpacing;
+ // The spacing between the bubbles and the borders of the bubble bar
+ private float mBubbleBarPadding;
// The size of a bubble in the bar
- private final float mIconSize;
+ private float mIconSize;
// The elevation of the bubbles within the bar
private final float mBubbleElevation;
private final float mDragElevation;
@@ -118,6 +120,7 @@
// 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.
@@ -169,16 +172,18 @@
setAlpha(0);
setVisibility(INVISIBLE);
mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
- mIconSpacing = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+ mBubbleBarPadding = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
mIconSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+ mExpandedBarIconsSpacing = getResources().getDimensionPixelSize(
+ 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,
- getResources().getDimensionPixelSize(R.dimen.bubblebar_size));
+ mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarHeight());
setBackgroundDrawable(mBubbleBarBackground);
mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
@@ -201,6 +206,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());
@@ -219,6 +225,29 @@
});
}
+ /**
+ * Sets new icon size and spacing between icons and bubble bar borders.
+ *
+ * @param newIconSize new icon size
+ * @param spacing spacing between icons and bubble bar borders.
+ */
+ // TODO(b/335575529): animate bubble bar icons size change
+ public void setIconSizeAndPadding(float newIconSize, float spacing) {
+ // TODO(b/335457839): handle new bubble animation during the size change
+ mBubbleBarPadding = spacing;
+ mIconSize = newIconSize;
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View childView = getChildAt(i);
+ FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
+ params.height = (int) mIconSize;
+ params.width = (int) mIconSize;
+ childView.setLayoutParams(params);
+ }
+ mBubbleBarBackground.setHeight(getBubbleBarHeight());
+ updateLayoutParams();
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -507,6 +536,10 @@
@Override
public void removeView(View view) {
super.removeView(view);
+ if (view == mSelectedBubbleView) {
+ mSelectedBubbleView = null;
+ mBubbleBarBackground.showArrow(false);
+ }
updateWidth();
}
@@ -516,6 +549,13 @@
setLayoutParams(lp);
}
+ private void updateLayoutParams() {
+ LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+ lp.height = getBubbleBarHeight();
+ lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
+ setLayoutParams(lp);
+ }
+
/** @return the horizontal margin between the bubble bar and the edge of the screen. */
int getHorizontalMargin() {
LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -551,12 +591,12 @@
final float collapsedX;
if (onLeft) {
// If bar is on the left, bubbles are ordered right to left
- expandedX = (bubbleCount - i - 1) * (mIconSize + mIconSpacing);
+ 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 + mIconSpacing);
+ expandedX = i * (mIconSize + mExpandedBarIconsSpacing);
collapsedX = i == 0 ? 0 : mIconOverlapAmount;
}
@@ -599,14 +639,14 @@
final float interpolatedWidth =
widthState * (expandedWidth - collapsedWidth) + collapsedWidth;
final float arrowPosition;
+
+ float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
if (onLeft) {
- float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
arrowPosition = collapsedArrowPosition + interpolatedShift;
} else {
if (mIsBarExpanded) {
- // when the bar is expanding, the selected bubble is always the first, so the arrow
- // always shifts with the interpolated width.
- arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition;
+ arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition
+ + interpolatedShift;
} else {
final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
arrowPosition =
@@ -655,8 +695,12 @@
* 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);
}
/**
@@ -681,6 +725,10 @@
// Find the center of the bubble when it's expanded, set the arrow position to it.
final float tx = arrowPositionForSelectedWhenExpanded();
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;
@@ -709,7 +757,8 @@
} else {
bubblePosition = index;
}
- return getPaddingStart() + bubblePosition * (mIconSize + mIconSpacing) + mIconSize / 2f;
+ return getPaddingStart() + bubblePosition * (mIconSize + mExpandedBarIconsSpacing)
+ + mIconSize / 2f;
}
private float arrowPositionForSelectedWhenCollapsed() {
@@ -770,7 +819,9 @@
public float expandedWidth() {
final int childCount = getChildCount();
final int horizontalPadding = getPaddingStart() + getPaddingEnd();
- return childCount * (mIconSize + mIconSpacing) + horizontalPadding;
+ // spaces amount is less than child count by 1, or 0 if no child views
+ int spacesCount = Math.max(childCount - 1, 0);
+ return childCount * mIconSize + spacesCount * mExpandedBarIconsSpacing + horizontalPadding;
}
private float collapsedWidth() {
@@ -783,6 +834,10 @@
: mIconSize + horizontalPadding;
}
+ private int getBubbleBarHeight() {
+ return (int) (mIconSize + mBubbleBarPadding * 2 + mPointerSize);
+ }
+
/**
* Returns whether the given MotionEvent, *in screen coordinates*, is within bubble bar
* touch bounds.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index aa1b4df..0e62eaf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,9 +18,12 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -52,12 +55,13 @@
public class BubbleBarViewController {
private static final String TAG = BubbleBarViewController.class.getSimpleName();
-
+ 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;
private final SystemUiProxy mSystemUiProxy;
private final TaskbarActivityContext mActivity;
private final BubbleBarView mBarView;
- private final int mIconSize;
- private final int mPointerSize;
+ private int mIconSize;
// Initialized in init.
private BubbleStashController mBubbleStashController;
@@ -96,9 +100,8 @@
mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
mBubbleBarAlpha.setUpdateVisibility(true);
- mIconSize = activity.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
- mPointerSize = activity.getResources().getDimensionPixelSize(
- R.dimen.bubblebar_pointer_size);
+ mIconSize = activity.getResources().getDimensionPixelSize(
+ R.dimen.bubblebar_icon_size);
}
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -108,12 +111,8 @@
mTaskbarStashController = controllers.taskbarStashController;
mTaskbarInsetsController = controllers.taskbarInsetsController;
- mActivity.addOnDeviceProfileChangeListener(dp ->
- mBarView.getLayoutParams().height =
- mActivity.getDeviceProfile().taskbarHeight + mPointerSize
- );
- mBarView.getLayoutParams().height =
- mActivity.getDeviceProfile().taskbarHeight + mPointerSize;
+ mActivity.addOnDeviceProfileChangeListener(dp -> setBubbleBarIconSize(dp.taskbarIconSize));
+ setBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize);
mBubbleBarScale.updateValue(1f);
mBubbleClickListener = v -> onBubbleClicked(v);
mBubbleBarClickListener = v -> onBubbleBarClicked();
@@ -260,12 +259,44 @@
}
}
+ private void setBubbleBarIconSize(int newIconSize) {
+ if (newIconSize == mIconSize) {
+ return;
+ }
+ Resources res = mActivity.getResources();
+ DisplayMetrics dm = res.getDisplayMetrics();
+ float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_SMALL_DP, dm);
+ float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_MEDIUM_DP, dm);
+ float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_LARGE_DP, dm);
+ float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
+ float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
+ mIconSize = newIconSize <= smallMediumThreshold
+ ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
+ res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+ float bubbleBarPadding = newIconSize >= mediumLargeThreshold
+ ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
+ res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+
+ mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
+ mBarView.setPadding((int) bubbleBarPadding, mBarView.getPaddingTop(),
+ (int) bubbleBarPadding,
+ mBarView.getPaddingBottom());
+ }
+
/** Sets a callback that updates the selected bubble after the bubble bar collapses. */
public void setUpdateSelectedBubbleAfterCollapse(
Consumer<String> updateSelectedBubbleAfterCollapse) {
mBarView.setUpdateSelectedBubbleAfterCollapse(updateSelectedBubbleAfterCollapse);
}
+ /** Returns whether the bubble bar should be hidden because of the current sysui state. */
+ boolean isHiddenForSysui() {
+ return mHiddenForSysui;
+ }
+
/**
* Sets whether the bubble bar should be hidden due to SysUI state (e.g. on lockscreen).
*/
@@ -340,10 +371,9 @@
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) {
+ boolean isInApp = mTaskbarStashController.isInApp();
+ // only animate the new bubble if we're in an app and not auto expanding
+ if (b instanceof BubbleBarBubble && isInApp && !isExpanding) {
mBubbleBarViewAnimator.animateBubbleInForStashed((BubbleBarBubble) b);
}
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 61a2e22..76d86de 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.view.InsetsController;
import android.view.MotionEvent;
+import android.view.View;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.StashedHandleViewController;
@@ -32,6 +33,7 @@
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
/**
* Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
@@ -51,15 +53,6 @@
*/
private static final float STASHED_BAR_SCALE = 0.5f;
- /** The duration of hiding and showing the stashed handle as part of a new bubble animation. */
- private static final long NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS = 200;
-
- /** The translation Y value the handle animates to when hiding it for a new bubble. */
- private static final int NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y = -20;
-
- /** The alpha value the handle animates to when hiding it for a new bubble. */
- public static final float NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA = 0.5f;
-
protected final TaskbarActivityContext mActivity;
// Initialized in init.
@@ -73,7 +66,6 @@
private AnimatedFloat mIconScaleForStash;
private AnimatedFloat mIconTranslationYForStash;
private MultiPropertyFactory.MultiProperty mBubbleStashedHandleAlpha;
- private AnimatedFloat mBubbleStashedHandleTranslationY;
private boolean mRequestedStashState;
private boolean mRequestedExpandedState;
@@ -105,7 +97,6 @@
mBubbleStashedHandleAlpha = mHandleViewController.getStashedHandleAlpha().get(
StashedHandleViewController.ALPHA_INDEX_STASHED);
- mBubbleStashedHandleTranslationY = mHandleViewController.getStashedHandleTranslationY();
mStashedHeight = mHandleViewController.getStashedHeight();
mUnstashedHeight = mHandleViewController.getUnstashedHeight();
@@ -379,29 +370,8 @@
return mHandleViewController.getStashedHandleCenterX();
}
- /** Returns the animation for hiding the handle before a new bubble animates in. */
- public AnimatorSet buildHideHandleAnimationForNewBubble() {
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playTogether(
- mBubbleStashedHandleTranslationY.animateToValue(
- NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y),
- mBubbleStashedHandleAlpha.animateToValue(NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA));
- animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
- return animatorSet;
- }
-
- /** Sets the alpha value of the stashed handle. */
- public void setStashAlpha(float alpha) {
- mBubbleStashedHandleAlpha.setValue(alpha);
- }
-
- /** Returns the animation for showing the handle after a new bubble animated in. */
- public AnimatorSet buildShowHandleAnimationForNewBubble() {
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playTogether(
- mBubbleStashedHandleTranslationY.animateToValue(0),
- mBubbleStashedHandleAlpha.animateToValue(1));
- animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
- return animatorSet;
+ /** Returns the [PhysicsAnimator] for the stashed handle view. */
+ public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
+ return mHandleViewController.getPhysicsAnimator();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 2a5912a..6f1a093 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -29,7 +29,6 @@
import android.view.ViewOutlineProvider;
import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.taskbar.StashedHandleView;
@@ -40,6 +39,7 @@
import com.android.launcher3.util.MultiValueAlpha;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
/**
* Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -59,12 +59,6 @@
private int mStashedHandleWidth;
private int mStashedHandleHeight;
- private final AnimatedFloat mStashedHandleTranslationY =
- new AnimatedFloat(this::updateTranslationY);
-
- // Modified when swipe up is happening on the stashed handle or task bar.
- private float mSwipeUpTranslationY;
-
// The bounds we want to clip to in the settled state when showing the stashed handle.
private final Rect mStashedHandleBounds = new Rect();
@@ -129,6 +123,11 @@
updateBounds(mBarViewController.getBubbleBarLocation()));
}
+ /** Returns the [PhysicsAnimator] for the stashed handle view. */
+ public PhysicsAnimator<View> getPhysicsAnimator() {
+ return PhysicsAnimator.getInstance(mStashedHandleView);
+ }
+
private void updateBounds(BubbleBarLocation bubbleBarLocation) {
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
// handle bar position, we pin it to the edge of the screen.
@@ -238,21 +237,11 @@
}
}
- /** Returns an animator for translation Y. */
- public AnimatedFloat getStashedHandleTranslationY() {
- return mStashedHandleTranslationY;
- }
-
/**
* Sets the translation of the stashed handle during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
- mSwipeUpTranslationY = transY;
- updateTranslationY();
- }
-
- private void updateTranslationY() {
- mStashedHandleView.setTranslationY(mStashedHandleTranslationY.value + mSwipeUpTranslationY);
+ mStashedHandleView.setTranslationY(transY);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
index edabae2..3f947a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -1,3 +1,5 @@
atsjenk@google.com
liranb@google.com
madym@google.com
+mpodolian@google.com
+
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 1db5103..2d8983f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -18,16 +18,12 @@
import android.view.View
import android.view.View.VISIBLE
-import androidx.core.animation.AnimatorSet
-import androidx.core.animation.ObjectAnimator
-import androidx.core.animation.doOnEnd
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce
import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleStashController
import com.android.launcher3.taskbar.bubbles.BubbleView
-import com.android.systemui.util.doOnEnd
import com.android.wm.shell.shared.animation.PhysicsAnimator
/** Handles animations for bubble bar bubbles. */
@@ -43,17 +39,19 @@
/** 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_FINAL_TRANSLATION_Y = -50f
+ 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_INITIAL_TRANSLATION_Y = 50f
+ 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 initial alpha value that the new bubble is set to before the animation starts. */
- const val BUBBLE_ANIMATION_INITIAL_ALPHA = 0.5f
- /** The duration of the hide bubble animation. */
- const val HIDE_BUBBLE_ANIMATION_DURATION_MS = 250L
+ /**
+ * 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
}
/** An interface for scheduling jobs. */
@@ -91,7 +89,7 @@
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, animator)
+ val showAnimation = buildShowAnimation(bubbleView, b.key)
val hideAnimation = buildHideAnimation(bubbleView)
scheduler.post(showAnimation)
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
@@ -100,71 +98,139 @@
/**
* Returns a lambda that starts the animation that shows the new bubble.
*
- * The animation is divided into 2 parts. First the stash handle starts animating up and fades
- * out. When it ends the bubble starts fading in. The bubble and stashed handle are aligned to
- * give the impression of the stash handle morphing into the bubble.
+ * 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.
+ *
+ * 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.
+ * 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
+ * visible which helps avoiding further updates when we re-enter the second part.
*/
private fun buildShowAnimation(
bubbleView: BubbleView,
key: String,
- bubbleAnimator: PhysicsAnimator<BubbleView>
): () -> 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
- bubbleBarView.prepareForAnimatingBubbleWhileStashed(key)
- bubbleAnimator.setDefaultSpringConfig(springConfig)
- bubbleAnimator
- .spring(DynamicAnimation.ALPHA, 1f)
- .spring(DynamicAnimation.TRANSLATION_Y, BUBBLE_ANIMATION_FINAL_TRANSLATION_Y)
- .spring(DynamicAnimation.SCALE_Y, 1f)
// prepare the bubble for the animation
bubbleView.alpha = 0f
bubbleView.translationX = initialTranslationX
- bubbleView.translationY = BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
bubbleView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
bubbleView.visibility = VISIBLE
- // start the stashed handle animation. when it ends, start the bubble animation.
- val stashedHandleAnimation = bubbleStashController.buildHideHandleAnimationForNewBubble()
- stashedHandleAnimation.doOnEnd {
- bubbleView.alpha = BUBBLE_ANIMATION_INITIAL_ALPHA
- bubbleAnimator.start()
- bubbleStashController.setStashAlpha(0f)
+
+ // 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
+ val animator = bubbleStashController.stashedHandlePhysicsAnimator
+ animator.setDefaultSpringConfig(springConfig)
+ animator.spring(DynamicAnimation.TRANSLATION_Y, totalTranslationY)
+ animator.addUpdateListener { target, values ->
+ val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+ when {
+ ty >= BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y -> {
+ // we're in the first leg of the animation. only animate the handle. the bubble
+ // 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
+ }
+ ty >= totalTranslationY -> {
+ // this is the second leg of the animation. the handle should be completely
+ // hidden and the bubble 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
+ // 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]
+ val fraction =
+ (ty - BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y) /
+ BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y
+ bubbleView.alpha = fraction
+ bubbleView.scaleY =
+ BUBBLE_ANIMATION_INITIAL_SCALE_Y +
+ (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+ }
+ }
+ 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
+ }
+ }
}
- stashedHandleAnimation.start()
+ animator.start()
}
/**
* Returns a lambda that starts the animation that hides the new bubble.
*
- * Similarly to the show animation, this is 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.
+ * 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.
+ *
+ * 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.
*/
private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = {
- val stashAnimation = bubbleStashController.buildShowHandleAnimationForNewBubble()
- val alphaAnimator =
- ObjectAnimator.ofFloat(bubbleView, View.ALPHA, BUBBLE_ANIMATION_INITIAL_ALPHA)
- val translationYAnimator =
- ObjectAnimator.ofFloat(
- bubbleView,
- View.TRANSLATION_Y,
- BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
- )
- val scaleYAnimator =
- ObjectAnimator.ofFloat(bubbleView, View.SCALE_Y, BUBBLE_ANIMATION_INITIAL_SCALE_Y)
- val hideBubbleAnimation = AnimatorSet()
- hideBubbleAnimation.playTogether(alphaAnimator, translationYAnimator, scaleYAnimator)
- hideBubbleAnimation.duration = HIDE_BUBBLE_ANIMATION_DURATION_MS
- hideBubbleAnimation.doOnEnd {
- // the bubble is now hidden, start the stash handle animation and reset bubble
- // properties
- bubbleStashController.setStashAlpha(
- BubbleStashController.NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA
- )
+ // 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
+ val animator = bubbleStashController.stashedHandlePhysicsAnimator
+ animator.setDefaultSpringConfig(springConfig)
+ animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
+ animator.addUpdateListener { target, 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 <= 0 -> {
+ // this is the second part of the animation. make the bubble 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
+ }
+ }
+ else -> {
+ // we reached the target value. set the alpha of the handle to 1
+ target.alpha = 1f
+ }
+ }
+ }
+ animator.addEndListener { _, _, _, _, _, _, _ ->
bubbleView.alpha = 0f
- stashAnimation.start()
bubbleView.translationY = 0f
bubbleView.scaleY = 1f
if (bubbleStashController.isStashed) {
@@ -172,7 +238,7 @@
}
bubbleBarView.onAnimatingBubbleCompleted()
}
- hideBubbleAnimation.start()
+ animator.start()
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 543fd02..4acddee 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1210,6 +1210,7 @@
switch (info.container) {
case Favorites.CONTAINER_DESKTOP:
case Favorites.CONTAINER_HOTSEAT:
+ case Favorites.CONTAINER_PRIVATESPACE:
// Fall through and continue it's on the workspace (we don't support swiping back
// to other containers like all apps or the hotseat predictions (which can change)
break;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 2fedb6f..8e4dde2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -38,8 +38,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;
@@ -1254,10 +1252,12 @@
return LAST_TASK;
}
- if (((mRecentsView.getNextPageTaskView() != null
- && mRecentsView.getNextPageTaskView().isDesktopTask())
- || (mRecentsView.getCurrentPageTaskView() != null
- && mRecentsView.getCurrentPageTaskView().isDesktopTask()))
+ TaskView nextPageTaskView = mRecentsView != null
+ ? 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;
@@ -1649,12 +1649,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
diff --git a/quickstep/src/com/android/quickstep/DesktopModeStatus.java b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
new file mode 100644
index 0000000..b1aae16
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
+
+// TODO(b/335401172): Explore unifying logic across core and shell
+public class DesktopModeStatus {
+
+ /**
+ * Flag to indicate whether to restrict desktop mode to supported devices.
+ */
+ private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean(
+ "persist.wm.debug.desktop_mode_enforce_device_restrictions", true);
+
+ /**
+ * Return {@code true} if desktop mode should be restricted to supported devices.
+ */
+ @VisibleForTesting
+ public static boolean enforceDeviceRestrictions() {
+ return ENFORCE_DEVICE_RESTRICTIONS;
+ }
+
+ /**
+ * Return {@code true} if the current device supports desktop mode.
+ */
+ @VisibleForTesting
+ public static boolean isDesktopModeSupported(Context context) {
+ return context.getResources().getBoolean(
+ com.android.internal.R.bool.config_isDesktopModeSupported);
+ }
+
+ /**
+ * Return {@code true} if desktop mode can be entered on the current device.
+ */
+ public static boolean canEnterDesktopMode(Context context) {
+ return Flags.enableDesktopWindowingMode()
+ && (!enforceDeviceRestrictions() || isDesktopModeSupported(context));
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index aa0f728..f26d594 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -24,7 +24,6 @@
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
-import com.android.window.flags.Flags
/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
class DesktopSystemShortcut(
@@ -52,7 +51,7 @@
}
companion object {
- /** Creates a factory for creating Desktop system shorcuts. */
+ /** Creates a factory for creating Desktop system shortcuts. */
@JvmOverloads
fun createFactory(
abstractFloatingViewHelper: AbstractFloatingViewHelper = AbstractFloatingViewHelper()
@@ -62,7 +61,7 @@
container: RecentsViewContainer,
taskContainer: TaskIdAttributeContainer
): List<DesktopSystemShortcut>? {
- return if (!Flags.enableDesktopWindowingMode()) null
+ return if (!DesktopModeStatus.canEnterDesktopMode(container.asContext())) null
else if (!taskContainer.task.isDockable) null
else
listOf(
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index a3935ce..af02ccf 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -122,6 +122,10 @@
float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
return new FloatingViewHomeAnimationFactory(floatingIconView) {
+ @Nullable
+ private RectF mTargetRect;
+ @Nullable
+ private RectFSpringAnim mSiblingAnimation;
@Nullable
@Override
@@ -138,15 +142,36 @@
@NonNull
@Override
public RectF getWindowTargetRect() {
- return iconLocation;
+ if (enableScalingRevealHomeAnimation()) {
+ if (mTargetRect == null) {
+ mTargetRect = new RectF(iconLocation);
+ }
+ return mTargetRect;
+ } else {
+ return iconLocation;
+ }
+ }
+
+ @Override
+ public void playAtomicAnimation(float velocity) {
+ if (enableScalingRevealHomeAnimation()) {
+ if (mContainer != null) {
+ new ScalingWorkspaceRevealAnim(
+ mContainer, mSiblingAnimation, getWindowTargetRect()).start();
+ }
+ } else {
+ super.playAtomicAnimation(velocity);
+ }
}
@Override
public void setAnimation(RectFSpringAnim anim) {
super.setAnimation(anim);
- anim.addAnimatorListener(floatingIconView);
- floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
- floatingIconView.setFastFinishRunnable(anim::end);
+ mSiblingAnimation = anim;
+ mSiblingAnimation.addAnimatorListener(floatingIconView);
+ floatingIconView.setOnTargetChangeListener(
+ mSiblingAnimation::onTargetPositionChanged);
+ floatingIconView.setFastFinishRunnable(mSiblingAnimation::end);
}
@Override
@@ -301,15 +326,9 @@
@Override
public void playAtomicAnimation(float velocity) {
- if (enableScalingRevealHomeAnimation()) {
- if (mContainer != null) {
- new ScalingWorkspaceRevealAnim(mContainer).start();
- }
- } else {
- new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
- }
+ new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
}
}
}
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/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 30bb863..b0b2589 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -16,6 +16,7 @@
package com.android.quickstep;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.content.pm.PackageManager.FEATURE_PC;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -23,6 +24,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 +35,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 +67,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,7 +111,7 @@
/**
* Holds the reference to SystemUI.
*/
-public class SystemUiProxy implements ISystemUiProxy, NavHandle {
+public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
private static final String TAG = SystemUiProxy.class.getSimpleName();
public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
@@ -199,6 +202,9 @@
}
@Override
+ public void close() { }
+
+ @Override
public void onBackPressed() {
if (mSystemUiProxy != null) {
try {
@@ -454,10 +460,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);
}
@@ -1366,8 +1373,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 +1383,12 @@
return new ArrayList<>();
}
+ private boolean shouldEnableRunningTasksForDesktopMode() {
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ return (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps())
+ || mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
+ }
+
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..9d899fc 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -59,6 +59,7 @@
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 +67,6 @@
private GestureState mLastGestureState;
private RemoteAnimationTarget[] mLastAppearedTaskTargets;
private Runnable mLiveTileCleanUpHandler;
- private Context mCtx;
private boolean mRecentsAnimationStartPending = false;
private boolean mShouldIgnoreMotionEvents = false;
@@ -329,7 +329,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..0d9564d 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -46,7 +46,7 @@
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.systemui.shared.recents.model.Task;
@@ -107,7 +107,7 @@
return shortcuts;
}
- public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
+ public TaskOverlay createOverlay(TaskThumbnailViewDeprecated thumbnailView) {
return new TaskOverlay(thumbnailView);
}
@@ -149,14 +149,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 +169,7 @@
return mActionsView;
}
- public TaskThumbnailView getThumbnailView() {
+ public TaskThumbnailViewDeprecated getThumbnailView() {
return mThumbnailView;
}
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 9d10ac1..94667a4 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -53,7 +53,7 @@
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.systemui.shared.recents.model.Task;
@@ -158,7 +158,7 @@
private Handler mHandler;
private final RecentsView mRecentsView;
- private final TaskThumbnailView mThumbnailView;
+ private final TaskThumbnailViewDeprecated mThumbnailView;
private final TaskView mTaskView;
private final LauncherEvent mLauncherEvent;
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..d89d399 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;
@@ -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.getThumbnails();
// 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/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index a09e027..ed633df 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -347,7 +347,6 @@
event.getId() + "";
Log.d(TAG, name);
}
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
if (mSlice == null && mSliceItem != null) {
mSlice = LauncherAtom.Slice.newBuilder().setUri(
@@ -369,15 +368,10 @@
return;
}
- if (mItemInfo.container < 0 || appState == null) {
- // 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 {
+ 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.
- appState.getModel().enqueueModelUpdateTask(
+ app.getModel().enqueueModelUpdateTask(
new BaseModelUpdateTask() {
@Override
public void execute(@NonNull final LauncherAppState app,
@@ -388,6 +382,11 @@
write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
}
});
+ })) {
+ // 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())));
}
}
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..d51069f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.util.AttributeSet
+import android.view.View
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.*
+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]
+ val viewModel = TaskThumbnailViewModel()
+
+ private var uiState: TaskThumbnailUiState = Uninitialized
+
+ 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()
+ }
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ when (uiState) {
+ is Uninitialized -> {}
+ is LiveTile -> drawTransparentUiState(canvas)
+ }
+ }
+
+ private fun drawTransparentUiState(canvas: Canvas) {
+ canvas.drawRoundRect(
+ 0f,
+ 0f,
+ measuredWidth.toFloat(),
+ measuredHeight.toFloat(),
+ // TODO(b/334826840) add rounded corners
+ 0f,
+ 0f,
+ CLEAR_PAINT
+ )
+ }
+
+ 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..9925873
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
@@ -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.task.thumbnail
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class TaskThumbnailViewModel {
+ private val _uiState: MutableStateFlow<TaskThumbnailUiState> =
+ MutableStateFlow(TaskThumbnailUiState.Uninitialized)
+ val uiState: StateFlow<TaskThumbnailUiState> = _uiState
+
+ fun bind(task: TaskThumbnail) {
+ _uiState.value =
+ if (task.isRunning) {
+ TaskThumbnailUiState.LiveTile
+ } else {
+ TaskThumbnailUiState.Uninitialized
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 2b4d280..a82031a 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -316,7 +316,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 +489,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 dcd3c6d..42db65f 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -33,13 +33,13 @@
public AssistStateManager() {}
- /** Whether search supports haptic on invocation. */
- public boolean supportsCommitHaptic() {
+ /** Whether search is available. */
+ public boolean isSearchAvailable() {
return false;
}
- /** Whether search is available. */
- public boolean isSearchAvailable() {
+ /** Whether search supports showing on the lockscreen. */
+ public boolean supportsShowWhenLocked() {
return false;
}
@@ -85,6 +85,11 @@
return 0;
}
+ /** Get the haptic bit overridden by AGSA. */
+ public Optional<Boolean> getShouldPlayHapticOverride() {
+ return Optional.empty();
+ }
+
/** Return {@code true} if the Settings toggle is enabled. */
public boolean isSettingsAllEntrypointsEnabled() {
return false;
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index c39056d..5505bb3 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -171,8 +171,13 @@
public void onTargetPositionChanged() {
if (enableScalingRevealHomeAnimation()) {
+ if (isEnded()) {
+ return;
+ }
+
if (mRectXSpring != null) {
mRectXSpring.animateToFinalPosition(mTargetRect.centerX());
+ mRectXAnimEnded = false;
}
if (mRectYSpring != null) {
@@ -187,6 +192,7 @@
mRectYSpring.animateToFinalPosition(mTargetRect.centerY());
break;
}
+ mRectYAnimEnded = false;
}
} else {
if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
@@ -297,6 +303,7 @@
.setStiffness(stiffnessZ)
.setDampingRatio(dampingZ))
.setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+ .setMaxValue(1f)
.setMinimumVisibleChange(minVisibleChange)
.addEndListener((animation, canceled, value, velocity) -> {
mRectScaleAnimEnded = true;
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index 0c1ac25..1bf77f1 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -16,7 +16,10 @@
package com.android.quickstep.util
+import android.graphics.Matrix
+import android.graphics.RectF
import android.view.View
+import androidx.core.graphics.transform
import com.android.app.animation.Interpolators
import com.android.app.animation.Interpolators.EMPHASIZED
import com.android.app.animation.Interpolators.LINEAR
@@ -38,7 +41,11 @@
* Creates an animation where the workspace and hotseat fade in while revealing from the center of
* the screen outwards radially. This is used in conjunction with the swipe up to home animation.
*/
-class ScalingWorkspaceRevealAnim(launcher: QuickstepLauncher) {
+class ScalingWorkspaceRevealAnim(
+ launcher: QuickstepLauncher,
+ siblingAnimation: RectFSpringAnim?,
+ windowTargetRect: RectF?
+) {
companion object {
private const val FADE_DURATION_MS = 200L
private const val SCALE_DURATION_MS = 1000L
@@ -118,6 +125,41 @@
transitionConfig
)
+ // To avoid awkward jumps in icon position, we want the sibling animation to always be
+ // targeting the current position. Since we can't easily access this, instead we calculate
+ // it using the animation of the whole of home.
+ // We start by caching the final target position, as this is the base for the transforms.
+ val originalTarget = RectF(windowTargetRect)
+ animation.addOnFrameListener {
+ val transformed = RectF(originalTarget)
+
+ // First we scale down using the same pivot as the workspace scale, so we find the
+ // correct position AND size.
+ transformed.transform(
+ Matrix().apply {
+ setScale(workspace.scaleX, workspace.scaleY, workspace.pivotX, workspace.pivotY)
+ }
+ )
+ // Then we scale back up around the center of the current position. This is because the
+ // icon animation behaves poorly if it is given a target that is smaller than the size
+ // of the icon.
+ transformed.transform(
+ Matrix().apply {
+ setScale(
+ 1 / workspace.scaleX,
+ 1 / workspace.scaleY,
+ transformed.centerX(),
+ transformed.centerY()
+ )
+ }
+ )
+
+ if (transformed != windowTargetRect) {
+ windowTargetRect?.set(transformed)
+ siblingAnimation?.onTargetPositionChanged()
+ }
+ }
+
// Needed to avoid text artefacts during the scale animation.
workspace.setLayerType(View.LAYER_TYPE_HARDWARE, null)
hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null)
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 378a00d..f430d79 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -65,7 +65,7 @@
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.TaskViewIcon
@@ -160,9 +160,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
@@ -179,7 +179,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 +202,7 @@
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
- TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X,
+ TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
centerThumbnailTranslationX
)
)
@@ -224,7 +224,7 @@
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
- TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+ TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
translateYResetVal
)
)
@@ -252,7 +252,7 @@
builder.add(
ObjectAnimator.ofFloat(
thumbnail,
- TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+ TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
centerThumbnailTranslationY
)
)
@@ -266,7 +266,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 +280,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
}
@@ -929,11 +949,30 @@
}
}
+ if (splitRoot1 != null) {
+ // Set the highest level split root alpha; we could technically use the parent of
+ // either splitRoot1 or splitRoot2
+ val parentToken = splitRoot1.parent
+ var rootLayer: Change? = null
+ if (parentToken != null) {
+ rootLayer = transitionInfo.getChange(parentToken)
+ }
+ if (rootLayer != null && rootLayer.leash != null) {
+ openingTargets.add(rootLayer.leash)
+ }
+ }
+
val animTransaction = Transaction()
val animator = ValueAnimator.ofFloat(0f, 1f)
animator.setDuration(QuickstepTransitionManager.SPLIT_LAUNCH_DURATION.toLong())
animator.addUpdateListener { valueAnimator: ValueAnimator ->
- val progress = valueAnimator.animatedFraction
+ val progress =
+ Interpolators.clampToProgress(
+ Interpolators.LINEAR,
+ valueAnimator.animatedFraction,
+ 0.8f,
+ 1f
+ )
for (leash in openingTargets) {
animTransaction.setAlpha(leash, progress)
}
@@ -955,19 +994,6 @@
}
)
- if (splitRoot1 != null) {
- // Set the highest level split root alpha; we could technically use the parent of
- // either splitRoot1 or splitRoot2
- val parentToken = splitRoot1.parent
- var rootLayer: Change? = null
- if (parentToken != null) {
- rootLayer = transitionInfo.getChange(parentToken)
- }
- if (rootLayer != null && rootLayer.leash != null) {
- t.setAlpha(rootLayer.leash, 1f)
- }
- }
-
t.apply()
animator.start()
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index d07acd4..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;
}
@@ -177,6 +177,11 @@
private boolean mIsCancelled = false;
@Override
+ public void onAnimationStart(Animator animation) {
+ mController.launchSplitTasks(aBoolean -> cleanUp());
+ }
+
+ @Override
public void onAnimationCancel(Animator animation) {
mIsCancelled = true;
cleanUp();
@@ -185,7 +190,6 @@
@Override
public void onAnimationEnd(Animator animation) {
if (!mIsCancelled) {
- mController.launchSplitTasks(aBoolean -> cleanUp());
InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
}
}
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/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 78b1763..93059b2 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
@@ -38,13 +39,13 @@
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.BaseContainerInterface;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.util.RecentsOrientedState;
@@ -74,10 +75,10 @@
@NonNull
private List<Task> mTasks = new ArrayList<>();
- private final ArrayList<TaskThumbnailView> mSnapshotViews = new ArrayList<>();
+ private final ArrayList<TaskThumbnailViewDeprecated> mSnapshotViews = new ArrayList<>();
- /** Maps {@code taskIds} to corresponding {@link TaskThumbnailView}s */
- private final SparseArray<TaskThumbnailView> mSnapshotViewMap = new SparseArray<>();
+ /** Maps {@code taskIds} to corresponding {@link TaskThumbnailViewDeprecated}s */
+ private final SparseArray<TaskThumbnailViewDeprecated> mSnapshotViewMap = new SparseArray<>();
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
@@ -87,6 +88,8 @@
private int mChildCountAtInflation;
+ private final PointF mTempPointF = new PointF();
+
public DesktopTaskView(Context context) {
this(context, null);
}
@@ -175,13 +178,14 @@
if (mSnapshotViews.size() > mTasks.size()) {
int diff = mSnapshotViews.size() - mTasks.size();
for (int i = 0; i < diff; i++) {
- TaskThumbnailView snapshotView = mSnapshotViews.remove(0);
+ TaskThumbnailViewDeprecated 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());
+ TaskThumbnailViewDeprecated snapshotView =
+ new TaskThumbnailViewDeprecated(getContext());
mSnapshotViews.add(snapshotView);
// Add snapshots from to position after the initial child views.
addView(snapshotView, mChildCountAtInflation,
@@ -191,7 +195,7 @@
for (int i = 0; i < mTasks.size(); i++) {
Task task = mTasks.get(i);
- TaskThumbnailView snapshotView = mSnapshotViews.get(i);
+ TaskThumbnailViewDeprecated snapshotView = mSnapshotViews.get(i);
snapshotView.bind(task);
mSnapshotViewMap.put(task.key.id, snapshotView);
}
@@ -217,13 +221,13 @@
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);
+ TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
mTaskIdAttributeContainer[i] = createAttributeContainer(task, thumbnailView);
}
}
private TaskIdAttributeContainer createAttributeContainer(Task task,
- TaskThumbnailView thumbnailView) {
+ TaskThumbnailViewDeprecated thumbnailView) {
return new TaskIdAttributeContainer(task, thumbnailView, createIconView(task),
STAGE_POSITION_UNDEFINED);
}
@@ -250,14 +254,14 @@
}
@Override
- public TaskThumbnailView getThumbnail() {
+ public TaskThumbnailViewDeprecated 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;
+ return mTaskThumbnailViewDeprecated;
}
@Override
@@ -277,7 +281,8 @@
for (Task task : mTasks) {
CancellableTask<?> thumbLoadRequest =
thumbnailCache.updateThumbnailInBackground(task, thumbnailData -> {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
+ TaskThumbnailViewDeprecated thumbnailView =
+ mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.setThumbnail(task, thumbnailData);
}
@@ -290,7 +295,7 @@
} else {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
for (Task task : mTasks) {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
+ TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.setThumbnail(null, null);
}
@@ -303,16 +308,7 @@
@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);
- }
+ // no-op
}
@Override
@@ -367,11 +363,11 @@
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();
+ SparseArray<TaskThumbnailViewDeprecated> thumbnailsToRefresh = mSnapshotViewMap.clone();
if (thumbnailDatas != null) {
for (Task task : mTasks) {
int key = task.key.id;
- TaskThumbnailView thumbnailView = thumbnailsToRefresh.get(key);
+ TaskThumbnailViewDeprecated thumbnailView = thumbnailsToRefresh.get(key);
ThumbnailData thumbnailData = thumbnailDatas.get(key);
if (thumbnailView != null && thumbnailData != null) {
thumbnailView.setThumbnail(task, thumbnailData);
@@ -388,8 +384,9 @@
}
@Override
- public TaskThumbnailView[] getThumbnails() {
- TaskThumbnailView[] thumbnails = new TaskThumbnailView[mSnapshotViewMap.size()];
+ public TaskThumbnailViewDeprecated[] getThumbnails() {
+ TaskThumbnailViewDeprecated[] thumbnails =
+ new TaskThumbnailViewDeprecated[mSnapshotViewMap.size()];
for (int i = 0; i < thumbnails.length; i++) {
thumbnails[i] = mSnapshotViewMap.valueAt(i);
}
@@ -402,7 +399,7 @@
// 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);
+ TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.setThumbnail(task, null);
}
@@ -428,8 +425,10 @@
return;
}
- int windowWidth = mContainer.getDeviceProfile().widthPx;
- int windowHeight = mContainer.getDeviceProfile().heightPx;
+ BaseContainerInterface.getTaskDimension(mContext, mContainer.getDeviceProfile(),
+ mTempPointF);
+ int windowWidth = (int) mTempPointF.x;
+ int windowHeight = (int) mTempPointF.y;
float scaleWidth = containerWidth / (float) windowWidth;
float scaleHeight = containerHeight / (float) windowHeight;
@@ -453,7 +452,7 @@
int thumbWidth = (int) (taskSize.width() * scaleWidth);
int thumbHeight = (int) (taskSize.height() * scaleHeight);
- TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
+ TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
if (thumbnailView != null) {
thumbnailView.measure(MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY));
@@ -495,7 +494,7 @@
mBackgroundView.setVisibility(VISIBLE);
}
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
+ TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.valueAt(i);
thumbnailView.getTaskOverlay().setFullscreenProgress(progress);
}
updateSnapshotRadius();
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 8fa5375..82ba30b 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;
@@ -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(
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
index 9e1c856..a593712 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -11,6 +11,7 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
@@ -43,6 +44,7 @@
import kotlin.Unit;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.function.Consumer;
@@ -58,9 +60,11 @@
*/
public class GroupedTaskView extends TaskView {
+ private static final String TAG = TaskView.class.getSimpleName();
@Nullable
private Task mSecondaryTask;
- private TaskThumbnailView mSnapshotView2;
+ // TODO(b/336612373): Support new TTV for GroupedTaskView
+ private TaskThumbnailViewDeprecated mSnapshotView2;
private TaskViewIcon mIconView2;
@Nullable
private CancellableTask<ThumbnailData> mThumbnailLoadRequest2;
@@ -68,7 +72,8 @@
private CancellableTask mIconLoadRequest2;
private final float[] mIcon2CenterCoords = new float[2];
private TransformingTouchDelegate mIcon2TouchDelegate;
- @Nullable private SplitBounds mSplitBoundsConfig;
+ @Nullable
+ private SplitBounds mSplitBoundsConfig;
private final DigitalWellBeingToast mDigitalWellBeingToast2;
public GroupedTaskView(Context context) {
@@ -91,13 +96,17 @@
return Unit.INSTANCE;
}
bounds.set(
- Math.min(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
+ Math.min(mTaskThumbnailViewDeprecated.getLeft() + Math.round(
+ mTaskThumbnailViewDeprecated.getTranslationX()),
mSnapshotView2.getLeft() + Math.round(mSnapshotView2.getTranslationX())),
- Math.min(mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
+ Math.min(mTaskThumbnailViewDeprecated.getTop() + Math.round(
+ mTaskThumbnailViewDeprecated.getTranslationY()),
mSnapshotView2.getTop() + Math.round(mSnapshotView2.getTranslationY())),
- Math.max(mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
+ Math.max(mTaskThumbnailViewDeprecated.getRight() + Math.round(
+ mTaskThumbnailViewDeprecated.getTranslationX()),
mSnapshotView2.getRight() + Math.round(mSnapshotView2.getTranslationX())),
- Math.max(mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()),
+ Math.max(mTaskThumbnailViewDeprecated.getBottom() + Math.round(
+ mTaskThumbnailViewDeprecated.getTranslationY()),
mSnapshotView2.getBottom() + Math.round(mSnapshotView2.getTranslationY())));
return Unit.INSTANCE;
}
@@ -130,7 +139,7 @@
if (mSplitBoundsConfig == null) {
return;
}
- mSnapshotView.getPreviewPositionHelper().setSplitBounds(
+ mTaskThumbnailViewDeprecated.getPreviewPositionHelper().setSplitBounds(
convertLauncherSplitBoundsToShell(splitBoundsConfig),
PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT);
mSnapshotView2.getPreviewPositionHelper().setSplitBounds(
@@ -258,7 +267,6 @@
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;
@@ -281,6 +289,8 @@
launchingExistingTaskView ? this : null, mTask.key.id,
mSecondaryTask.key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
callback, isQuickswitch, getSnapPosition());
+ Log.d(TAG, "launchTaskInternal - launchExistingSplitPair: " + Arrays.toString(
+ getTaskIds()));
}
@Override
@@ -304,8 +314,8 @@
}
@Override
- public TaskThumbnailView[] getThumbnails() {
- return new TaskThumbnailView[]{mSnapshotView, mSnapshotView2};
+ public TaskThumbnailViewDeprecated[] getThumbnails() {
+ return new TaskThumbnailViewDeprecated[]{mTaskThumbnailViewDeprecated, mSnapshotView2};
}
@Override
@@ -349,20 +359,24 @@
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
- if (mSplitBoundsConfig == null || mSnapshotView == null || mSnapshotView2 == null) {
+ if (mSplitBoundsConfig == null || mTaskThumbnailViewDeprecated == null
+ || mSnapshotView2 == null) {
return;
}
int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
if (initSplitTaskId == INVALID_TASK_ID) {
- getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
+ getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(
+ mTaskThumbnailViewDeprecated,
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());
+ mTaskThumbnailViewDeprecated.applySplitSelectTranslateX(
+ mTaskThumbnailViewDeprecated.getTranslationX());
+ mTaskThumbnailViewDeprecated.applySplitSelectTranslateY(
+ mTaskThumbnailViewDeprecated.getTranslationY());
mSnapshotView2.applySplitSelectTranslateX(mSnapshotView2.getTranslationX());
mSnapshotView2.applySplitSelectTranslateY(mSnapshotView2.getTranslationY());
} else {
@@ -446,8 +460,9 @@
mSplitBoundsConfig);
} else {
getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
- taskIconHeight, mSnapshotView.getMeasuredWidth(),
- mSnapshotView.getMeasuredHeight(), getMeasuredHeight(), getMeasuredWidth(),
+ taskIconHeight, mTaskThumbnailViewDeprecated.getMeasuredWidth(),
+ mTaskThumbnailViewDeprecated.getMeasuredHeight(), getMeasuredHeight(),
+ getMeasuredWidth(),
isRtl, deviceProfile, mSplitBoundsConfig);
}
}
@@ -510,12 +525,12 @@
@Override
void setThumbnailVisibility(int visibility, int taskId) {
if (visibility == VISIBLE) {
- mSnapshotView.setVisibility(visibility);
+ mTaskThumbnailViewDeprecated.setVisibility(visibility);
mDigitalWellBeingToast.setBannerVisibility(visibility);
mSnapshotView2.setVisibility(visibility);
mDigitalWellBeingToast2.setBannerVisibility(visibility);
} else if (taskId == getTaskIds()[0]) {
- mSnapshotView.setVisibility(visibility);
+ mTaskThumbnailViewDeprecated.setVisibility(visibility);
mDigitalWellBeingToast.setBannerVisibility(visibility);
} else {
mSnapshotView2.setVisibility(visibility);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 791ef04..5daafcf 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -68,7 +68,6 @@
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SCREEN;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SELECT_ACTIVE;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -131,6 +130,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;
@@ -167,6 +167,7 @@
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewPool;
import com.android.quickstep.BaseContainerInterface;
+import com.android.quickstep.DesktopModeStatus;
import com.android.quickstep.GestureState;
import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.RecentsAnimationController;
@@ -1045,8 +1046,9 @@
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;
@@ -1833,7 +1835,7 @@
// the full list of tasks to taskViews
newRunningTaskView = getTaskViewByTaskIds(runningTaskId);
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 +1844,7 @@
// the current running task is excludedFromRecents.)
showCurrentTask(mActiveGestureRunningTasks);
} else {
- mRunningTaskViewId = INVALID_TASK_ID;
+ setRunningTaskViewId(INVALID_TASK_ID);
}
}
}
@@ -2734,18 +2736,22 @@
* 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;
+ TaskView taskView = getTaskViewByTaskId(runningTasks[0].key.id);
+ if (taskView == null) {
+ // No TaskView found, add a stub task.
+ return true;
}
- Task runningTaskInfo = runningTasks[0];
- return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.key.id) == null;
+
+ if (runningTasks.length > 1) {
+ // Ensure all taskIds matches the TaskView, otherwise add a stub task.
+ return Arrays.stream(runningTasks).anyMatch(
+ runningTask -> !taskView.containsTaskId(runningTask.key.id));
+ } else {
+ // Ensure the TaskView only contains a single taskId, or is a DesktopTask,
+ // otherwise add a stub task.
+ // TODO(b/249371338): Figure out why DesktopTask only have a single runningTask.
+ return taskView.containsMultipleTasks() && !taskView.isDesktopTask();
+ }
}
/**
@@ -2817,7 +2823,7 @@
}
private boolean hasDesktopTask(Task[] runningTasks) {
- if (!enableDesktopWindowingMode()) {
+ if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
return false;
}
for (Task task : runningTasks) {
@@ -2842,7 +2848,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) {
@@ -4762,7 +4784,7 @@
mSplitSelectStateController.getInitialTaskId();
TaskIdAttributeContainer taskIdAttributeContainer = mSplitHiddenTaskView
.getTaskIdAttributeContainers()[primaryTaskSelected ? 1 : 0];
- TaskThumbnailView thumbnail = taskIdAttributeContainer.getThumbnailView();
+ TaskThumbnailViewDeprecated thumbnail = taskIdAttributeContainer.getThumbnailView();
mSplitSelectStateController.getSplitAnimationController()
.addInitialSplitFromPair(taskIdAttributeContainer, builder,
mContainer.getDeviceProfile(),
@@ -5865,7 +5887,7 @@
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 {
@@ -6229,7 +6251,7 @@
*/
public void moveTaskToDesktop(TaskIdAttributeContainer taskContainer,
Runnable successCallback) {
- if (!enableDesktopWindowingMode()) {
+ if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
return;
}
switchToScreenshot(() -> finishRecentsAnimation(/* toRecents= */true, /* shouldPip= */false,
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index fcbb45b..5b0702a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -22,7 +22,7 @@
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;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index c124f03..1db04a8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -347,7 +347,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..9802beb 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
@@ -62,61 +62,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 {
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 +161,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 +186,6 @@
/**
* Updates the thumbnail to draw the provided task
- * @param task
*/
public void bind(Task task) {
getTaskOverlay().reset();
@@ -194,6 +199,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 +233,7 @@
/**
* Updates the shader, paint, matrix to redraw.
+ *
* @param shouldRefreshOverlay whether to re-initialize overlay
*/
private void refresh(boolean shouldRefreshOverlay) {
@@ -253,7 +260,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 +292,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)
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ec57115..c90e789 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -25,13 +25,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;
@@ -93,6 +92,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 +107,8 @@
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.util.ActiveGestureLog;
import com.android.quickstep.util.BorderAnimator;
import com.android.quickstep.util.RecentsOrientedState;
@@ -118,6 +120,8 @@
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;
@@ -126,7 +130,6 @@
import java.util.function.Consumer;
import java.util.stream.Stream;
-import kotlin.Unit;
/**
* A task in the Recents view.
@@ -319,13 +322,15 @@
@Override
public Float get(TaskView taskView) {
- return taskView.mSnapshotView.getScaleX();
+ return taskView.mTaskThumbnailViewDeprecated.getScaleX();
}
};
@Nullable
protected Task mTask;
- protected TaskThumbnailView mSnapshotView;
+ @Nullable // can be null when enableRefactorTaskThumbnail() == true
+ protected TaskThumbnailViewDeprecated mTaskThumbnailViewDeprecated;
+ protected TaskThumbnailView mTaskThumbnailView;
protected TaskViewIcon mIconView;
protected final DigitalWellBeingToast mDigitalWellBeingToast;
protected float mFullscreenProgress;
@@ -464,10 +469,11 @@
}
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()));
+ View snapshotView = getSnapshotView();
+ 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,6 +486,17 @@
}
/**
+ * 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 (mTask != null) {
+ bindTaskThumbnailView();
+ }
+ }
+
+ /**
* Builds proto for logging
*/
public WorkspaceItemInfo getItemInfo() {
@@ -516,7 +533,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);
@@ -649,15 +673,25 @@
*/
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,
+ mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task,
+ mTaskThumbnailViewDeprecated, mIconView,
STAGE_POSITION_UNDEFINED);
- mSnapshotView.bind(task);
+ if (enableRefactorTaskThumbnail()) {
+ bindTaskThumbnailView();
+ } else {
+ mTaskThumbnailViewDeprecated.bind(task);
+ }
setOrientationState(orientedState);
}
+ 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(mTask, isRunningTask()));
+ }
+
/**
* Sets up an on-click listener and the visibility for show_windows icon on top of the task.
*/
@@ -747,25 +781,29 @@
return null;
}
- public TaskThumbnailView getThumbnail() {
- return mSnapshotView;
+ public TaskThumbnailViewDeprecated getThumbnail() {
+ return mTaskThumbnailViewDeprecated;
}
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ if (enableRefactorTaskThumbnail()) {
+ // TODO(b/334825222) add thumbnail logic
+ return;
+ }
if (mTask != null && thumbnailDatas != null) {
final ThumbnailData thumbnailData = thumbnailDatas.get(mTask.key.id);
if (thumbnailData != null) {
- mSnapshotView.setThumbnail(mTask, thumbnailData);
+ mTaskThumbnailViewDeprecated.setThumbnail(mTask, 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[] getThumbnails() {
+ return new TaskThumbnailViewDeprecated[]{mTaskThumbnailViewDeprecated};
}
public TaskViewIcon getIconView() {
@@ -863,11 +901,7 @@
*/
@Nullable
public RunnableList launchTaskAnimated() {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTaskAnimated: mTask=" + mTask);
if (mTask != null) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTaskAnimated: startActivityFromRecentsAsync");
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
ActivityOptionsWrapper opts = mContainer.getActivityLaunchOptions(this, null);
@@ -875,6 +909,8 @@
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (ActivityManagerWrapper.getInstance()
.startActivityFromRecents(mTask.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 +936,7 @@
return null;
}
} else {
+ Log.d(TAG, "launchTaskAnimated - mTask is null");
return null;
}
}
@@ -915,15 +952,12 @@
* 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");
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
- 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
@@ -950,18 +984,17 @@
// 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());
+ // TODO(b/334826842) add splash functionality to new TTV
+ if (!enableRefactorTaskThumbnail()) {
+ opts.setDisableStartingWindow(mTaskThumbnailViewDeprecated.shouldShowSplashView());
+ }
Task.TaskKey key = mTask.key;
UI_HELPER_EXECUTOR.execute(() -> {
if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
@@ -986,9 +1019,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 +1045,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"
@@ -1037,8 +1065,6 @@
@Override
public void onAnimationEnd(Animator animator) {
if (mTask != null && mTask.key.displayId != getRootViewDisplayId()) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTasks: onAnimationEnd");
launchTaskAnimated();
}
mIsClickableAsLiveTile = true;
@@ -1055,6 +1081,8 @@
}
});
anim.start();
+ Log.d(TAG, "launchTasks - composeRecentsLaunchAnimator: " + Arrays.toString(
+ getTaskIds()));
recentsView.onTaskLaunchedInLiveTileMode();
return runnableList;
} else {
@@ -1089,7 +1117,10 @@
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
mTask, thumbnail -> {
- mSnapshotView.setThumbnail(mTask, thumbnail);
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334825222) add thumbnail state
+ mTaskThumbnailViewDeprecated.setThumbnail(mTask, thumbnail);
+ }
});
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
@@ -1107,7 +1138,10 @@
}
} 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;
@@ -1215,11 +1249,15 @@
// 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);
+ // 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(mTask);
}
@@ -1308,7 +1346,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 +1362,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(mTask, null);
+ }
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
mBorderEnabled = false;
@@ -1336,10 +1382,10 @@
super.onLayout(changed, left, top, right, bottom);
if (mContainer.getDeviceProfile().isTablet) {
setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
- setPivotY(mSnapshotView.getTop());
+ setPivotY(getSnapshotView().getTop());
} else {
setPivotX((right - left) * 0.5f);
- setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
+ setPivotY(getSnapshotView().getTop() + getSnapshotView().getHeight() * 0.5f);
}
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
@@ -1407,11 +1453,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) {
@@ -1690,7 +1742,11 @@
progress = Utilities.boundToRange(progress, 0, 1);
mFullscreenProgress = progress;
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
- mSnapshotView.getTaskOverlay().setFullscreenProgress(progress);
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334826840) Add corner rounding to new TTV
+ 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 +1759,10 @@
protected void updateSnapshotRadius() {
updateCurrentFullscreenParams();
- mSnapshotView.setFullscreenParams(mCurrentFullscreenParams);
+ if (!enableRefactorTaskThumbnail()) {
+ // TODO(b/334826840) Add corner rounding to new TTV
+ mTaskThumbnailViewDeprecated.setFullscreenParams(mCurrentFullscreenParams);
+ }
}
void updateCurrentFullscreenParams() {
@@ -1816,7 +1875,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,7 +1891,10 @@
* 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);
}
@@ -1854,10 +1920,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,10 +1962,13 @@
Utilities.mapRange(fullscreenProgress, mCornerRadius, mWindowCornerRadius)
/ parentScale / taskViewScale;
}
+
+ @Override
+ public void close() { }
}
public class TaskIdAttributeContainer {
- private final TaskThumbnailView mThumbnailView;
+ 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 */
@@ -1903,7 +1976,7 @@
@IdRes
private final int mA11yNodeId;
- public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
+ public TaskIdAttributeContainer(Task task, TaskThumbnailViewDeprecated thumbnailView,
TaskViewIcon iconView, int stagePosition) {
this.mTask = task;
this.mThumbnailView = thumbnailView;
@@ -1913,7 +1986,7 @@
R.id.split_bottomRight_appInfo : R.id.split_topLeft_appInfo;
}
- public TaskThumbnailView getThumbnailView() {
+ public TaskThumbnailViewDeprecated getThumbnailView() {
return mThumbnailView;
}
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/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index b478efa..d90e048 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
@@ -16,19 +16,15 @@
package com.android.launcher3.taskbar.bubbles.animation
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.AnimatorSet
import android.content.Context
import android.graphics.Color
import android.graphics.Path
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.animation.AnimatorTestRule
-import androidx.core.animation.doOnEnd
import androidx.core.graphics.drawable.toBitmap
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.test.core.app.ApplicationProvider
@@ -42,16 +38,13 @@
import com.android.launcher3.taskbar.bubbles.BubbleStashController
import com.android.launcher3.taskbar.bubbles.BubbleView
import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
import org.junit.Before
-import org.junit.ClassRule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
-import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@SmallTest
@@ -61,10 +54,6 @@
private val context = ApplicationProvider.getApplicationContext<Context>()
private val animatorScheduler = TestBubbleBarViewAnimatorScheduler()
- companion object {
- @JvmField @ClassRule val animatorTestRule = AnimatorTestRule()
- }
-
@Before
fun setUp() {
PhysicsAnimatorTestUtils.prepareForTest()
@@ -99,14 +88,9 @@
val bubbleStashController = mock<BubbleStashController>()
whenever(bubbleStashController.isStashed).thenReturn(true)
- val semaphore = Semaphore(0)
- val hideHandleAnimator = AnimatorSet()
- hideHandleAnimator.duration = 0
- whenever(bubbleStashController.buildHideHandleAnimationForNewBubble())
- .thenReturn(hideHandleAnimator)
- // add an end listener to the hide handle animation. we add it when the animation starts
- // to ensure that it gets called after all other end listeners.
- hideHandleAnimator.doOnStart { hideHandleAnimator.doOnEnd { semaphore.release() } }
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
val animator =
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
@@ -115,44 +99,26 @@
animator.animateBubbleInForStashed(bubble)
}
- // wait for the stash handle animation to complete
- assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
- // stash handle animation finished. verify that the stash handle is now hidden
- verify(bubbleStashController).setStashAlpha(0f)
-
+ // 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)
-
- // wait for the show bubble animation to complete
- PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(
- DynamicAnimation.ALPHA,
- DynamicAnimation.TRANSLATION_Y,
- DynamicAnimation.SCALE_Y,
- )
-
assertThat(bubbleView.alpha).isEqualTo(1)
- assertThat(bubbleView.translationY).isEqualTo(-50)
+ assertThat(bubbleView.translationY).isEqualTo(-20)
assertThat(bubbleView.scaleY).isEqualTo(1)
- val showHandleAnimator = AnimatorSet()
- showHandleAnimator.duration = 0
- whenever(bubbleStashController.buildShowHandleAnimationForNewBubble())
- .thenReturn(showHandleAnimator)
- var showHandleAnimationStarted = false
- showHandleAnimator.doOnStart { showHandleAnimationStarted = true }
-
// execute the hide bubble animation
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
- // finish the hide bubble animation
- InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animatorTestRule.advanceTimeBy(250)
- }
- assertThat(showHandleAnimationStarted).isTrue()
+ // 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)
@@ -160,16 +126,8 @@
assertThat(bubbleBarView.alpha).isEqualTo(0)
assertThat(overflowView.alpha).isEqualTo(1)
assertThat(overflowView.visibility).isEqualTo(VISIBLE)
- }
-
- private fun AnimatorSet.doOnStart(onStart: () -> Unit) {
- addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animator: Animator) {
- onStart()
- }
- }
- )
+ assertThat(handle.alpha).isEqualTo(1)
+ assertThat(handle.translationY).isEqualTo(0)
}
private class TestBubbleBarViewAnimatorScheduler : BubbleBarViewAnimator.Scheduler {
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..e71192f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.systemui.shared.recents.model.Task
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TaskThumbnailViewModelTest {
+ private val systemUnderTest = TaskThumbnailViewModel()
+
+ @Test
+ fun initialStateIsUninitialized() {
+ assertThat(systemUnderTest.uiState.value).isEqualTo(TaskThumbnailUiState.Uninitialized)
+ }
+
+ @Test
+ fun bindRunningTask_thenStateIs_LiveTile() {
+ val taskThumbnail = TaskThumbnail(Task(), isRunning = true)
+ systemUnderTest.bind(taskThumbnail)
+
+ assertThat(systemUnderTest.uiState.value).isEqualTo(TaskThumbnailUiState.LiveTile)
+ }
+
+ @Test
+ fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() {
+ // 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.value).isEqualTo(TaskThumbnailUiState.LiveTile)
+
+ systemUnderTest.bind(stoppedTask)
+ assertThat(systemUnderTest.uiState.value).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..93eefe2
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
@@ -0,0 +1,205 @@
+/*
+ * 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 android.util.SparseArray
+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_null_returnsNull() {
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(/* hotseatItems= */ null))
+ .isNull()
+ }
+
+ @Test
+ fun updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItems() {
+ setInDesktopMode(false)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ .toTypedArray()
+
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems))
+ .isEqualTo(hotseatItems)
+ }
+
+ @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(createSparseArray(hotseatItems))
+
+ val newHotseatItems =
+ taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+ assertThat(newHotseatItems?.map { it.targetPackage }).isEqualTo(hotseatPackages)
+ }
+
+ @Test
+ fun updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItems() {
+ setInDesktopMode(true)
+ val hotseatItems: Array<ItemInfo> =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ .toTypedArray()
+
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems))
+ .isEqualTo(hotseatItems)
+ }
+
+ @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(createSparseArray(hotseatItems))
+
+ 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(createSparseArray(hotseatItems))
+
+ 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)
+ }
+
+ 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 fun createSparseArray(itemInfos: List<ItemInfo>): SparseArray<ItemInfo> {
+ val sparseArray = SparseArray<ItemInfo>()
+ itemInfos.forEachIndexed { index, itemInfo -> sparseArray[index] = itemInfo }
+ return sparseArray
+ }
+
+ 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/launcher3/taskbar/bubbles/OWNERS b/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS
new file mode 100644
index 0000000..3f947a0
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -0,0 +1,5 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+mpodolian@google.com
+
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 7dabbca..0f9d96c 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -16,12 +16,14 @@
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.launcher3.AbstractFloatingView
import com.android.launcher3.AbstractFloatingViewHelper
-import com.android.launcher3.Launcher
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.model.data.WorkspaceItemInfo
@@ -33,8 +35,11 @@
import com.android.systemui.shared.recents.model.Task.TaskKey
import com.android.window.flags.Flags
import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.mockito.quality.Strictness
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
@@ -56,8 +61,23 @@
private val factory: TaskShortcutFactory =
DesktopSystemShortcut.createFactory(abstractFloatingViewHelper)
+ private lateinit var mockitoSession: StaticMockitoSession
+
+ @Before
+ 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(){
+ mockitoSession.finishMocking()
+ }
+
@Test
- fun createDesktopTaskShortcutFactory_featureOff() {
+ fun createDesktopTaskShortcutFactory_desktopModeDisabled() {
setFlagsRule.disableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
val task =
@@ -77,6 +97,49 @@
}
@Test
+ fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+
+ val task =
+ Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+ isDockable = true
+ }
+ val taskContainer =
+ taskView.TaskIdAttributeContainer(
+ task,
+ null,
+ null,
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ )
+
+ val shortcuts = factory.getShortcuts(launcher, taskContainer)
+ assertThat(shortcuts).isNull()
+ }
+
+ @Test
+ fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported_OverrideEnabled() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+ doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
+
+ val task =
+ Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+ isDockable = true
+ }
+ val taskContainer =
+ taskView.TaskIdAttributeContainer(
+ task,
+ null,
+ null,
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ )
+
+ val shortcuts = factory.getShortcuts(launcher, taskContainer)
+ assertThat(shortcuts).isNotNull()
+ }
+
+ @Test
fun createDesktopTaskShortcutFactory_undockable() {
setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
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/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 0c143b4..edc0a6f 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
import android.util.Log;
@@ -29,6 +28,9 @@
import androidx.test.filters.LargeTest;
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.Test;
@@ -42,7 +44,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 +55,6 @@
initialize(this);
createAndStartPrivateProfileUser();
- assumeTrue("Private Profile Setup not successful, aborting",
- mPrivateProfileSetupSuccessful);
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -71,7 +73,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,23 +87,42 @@
@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
+ @ScreenRecordRule.ScreenRecord // b/334946529
public void testPrivateSpaceContainerIsPresent() {
- assumeTrue(mPrivateProfileSetupSuccessful);
// Scroll to the bottom of All Apps
executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
- waitForResumed("Launcher internal state is still Background");
// Verify Unlocked View elements are present.
assertNotNull("Private Space Unlocked View not found, or is not correct",
mLauncher.getAllApps().getPrivateSpaceUnlockedView());
}
+ @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());
+
+ // Verify the Installed App is displayed in correct position.
+ PrivateSpaceContainer psContainer = mLauncher.getAllApps().getPrivateSpaceUnlockedView();
+ psContainer.verifyInstalledAppIsPresent(INSTALLED_APP_NAME);
+ }
+
private void waitForPrivateSpaceSetup() {
waitForLauncherCondition("Private Profile not setup",
launcher -> launcher.getAppsView().hasPrivateProfile(),
@@ -127,7 +148,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 +156,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/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..1556aa5 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -30,6 +30,7 @@
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.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.After;
@@ -84,6 +85,7 @@
@Test
@PortraitLandscape
@NavigationModeSwitch
+ @ScreenRecordRule.ScreenRecord // b/335674307
public void switchToOverview() throws Exception {
assumeTrue(mLauncher.isTablet());
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..4ffb6bd 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -31,7 +31,7 @@
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.systemui.shared.recents.model.Task
@@ -55,7 +55,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()
@@ -200,7 +200,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 +228,16 @@
verify(spySplitAnimationController)
.composeRecentsSplitLaunchAnimatorLegacy(
- any(), any(), any(), any(), any(), any(), any(), any(), any())
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any()
+ )
}
@Test
diff --git a/res/drawable/ic_private_profile_app_scroller_badge.xml b/res/drawable/ic_private_profile_app_scroller_badge.xml
new file mode 100644
index 0000000..ede42b9
--- /dev/null
+++ b/res/drawable/ic_private_profile_app_scroller_badge.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+ android:viewportWidth="32"
+ android:viewportHeight="32"
+ android:width="32dp"
+ android:height="32dp">
+ <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: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:attr/textColorPrimaryInverse" />
+</vector>
diff --git a/res/drawable/widget_picker_preview_pane_scroll_thumb.xml b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
new file mode 100644
index 0000000..24f90b0
--- /dev/null
+++ b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
@@ -0,0 +1,31 @@
+<?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.
+ -->
+<!--
+A variation of material's scrollbar_handle_material.xml that has paddings to make it smaller.
+ScrollView's "insideInsets" / "insideOverlay" styles don't consider corner radius applied to scroll
+views, so we apply matching padding to the thumb to align it.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:bottom="@dimen/widget_list_top_bottom_corner_radius"
+ android:top="@dimen/widget_list_top_bottom_corner_radius">
+ <shape
+ android:shape="rectangle"
+ android:tint="?android:attr/colorControlNormal">
+ <solid android:color="#84ffffff" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/work_mode_fab_background.xml b/res/drawable/work_mode_fab_background.xml
index 478b887..6be33e8 100644
--- a/res/drawable/work_mode_fab_background.xml
+++ b/res/drawable/work_mode_fab_background.xml
@@ -19,9 +19,6 @@
<shape android:shape="rectangle">
<corners android:radius="@dimen/work_fab_radius" />
<solid android:color="@color/work_fab_bg_color" />
- <padding
- android:left="@dimen/work_profile_footer_padding"
- android:right="@dimen/work_profile_footer_padding" />
</shape>
</item>
</ripple>
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 185207b..cefe394 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -24,7 +24,10 @@
android:background="@drawable/bg_ps_header"
android:clipToOutline="true"
android:gravity="center_vertical"
- android:orientation="horizontal">
+ android:textDirection="locale"
+ android:orientation="horizontal"
+ android:contentDescription="@string/ps_container_lock_button_content_description"
+ android:importantForAccessibility="yes">
<LinearLayout
android:id="@+id/settingsAndLockGroup"
@@ -39,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
@@ -48,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"
@@ -95,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..8f786bf 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -78,7 +78,7 @@
android:gravity="center_horizontal"
android:textSize="@dimen/widget_cell_font_size"
android:textColor="?android:attr/textColorSecondary"
- android:maxLines="2"
+ android:maxLines="3"
android:ellipsize="end"
android:fadingEdge="horizontal"
android:alpha="0.7" />
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_two_pane_sheet.xml b/res/layout/widgets_two_pane_sheet.xml
index 6c4810c..bb2b7bd 100644
--- a/res/layout/widgets_two_pane_sheet.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -94,42 +94,49 @@
</FrameLayout>
<FrameLayout
- android:id="@+id/right_pane_container"
android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="0.67"
- android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
- android:paddingTop="@dimen/widget_list_horizontal_margin_two_pane"
- android:gravity="end"
- android:layout_gravity="end"
- android:orientation="horizontal">
- <ScrollView
- android:id="@+id/right_pane_scroll_view"
+ android:layout_weight="0.67">
+ <FrameLayout
+ android:id="@+id/right_pane_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fillViewport="true">
- <LinearLayout
- android:orientation="vertical"
+ android:layout_marginVertical="@dimen/widget_picker_vertical_margin_right_pane"
+ android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
+ android:gravity="end"
+ android:layout_gravity="end"
+ android:orientation="horizontal">
+ <ScrollView
+ android:id="@+id/right_pane_scroll_view"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:clipToOutline="true"
- android:paddingBottom="36dp"
+ android:layout_height="match_parent"
android:background="@drawable/widgets_surface_background"
- android:importantForAccessibility="yes"
- android:id="@+id/right_pane">
- <!-- Shown when there are recommendations to display -->
+ android:scrollbarThumbVertical="@drawable/widget_picker_preview_pane_scroll_thumb"
+ android:clipToOutline="true"
+ android:fillViewport="true">
<LinearLayout
- android:id="@+id/widget_recommendations_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/widgets_surface_background"
android:orientation="vertical"
- android:visibility="gone">
- <include layout="@layout/widget_recommendations" />
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:clipToOutline="true"
+ android:paddingBottom="36dp"
+ android:background="@drawable/widgets_surface_background"
+ android:importantForAccessibility="yes"
+ android:id="@+id/right_pane">
+ <!-- Shown when there are recommendations to display -->
+ <LinearLayout
+ android:id="@+id/widget_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/widgets_surface_background"
+ android:orientation="vertical"
+ android:visibility="gone">
+ <include layout="@layout/widget_recommendations" />
+ </LinearLayout>
</LinearLayout>
- </LinearLayout>
- </ScrollView>
+ </ScrollView>
+ </FrameLayout>
</FrameLayout>
</LinearLayout>
</com.android.launcher3.views.SpringRelativeLayout>
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 276d73e..b3484c9 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -24,12 +24,15 @@
android:background="@drawable/work_mode_fab_background"
android:forceHasOverlappingRendering="false"
android:contentDescription="@string/work_apps_pause_btn_text"
+ android:paddingStart="@dimen/work_mode_fab_background_start_padding"
+ android:paddingEnd="@dimen/work_mode_fab_background_end_padding"
android:animateLayoutChanges="true">
<ImageView
android:id="@+id/work_icon"
android:layout_width="@dimen/work_fab_icon_size"
android:layout_height="@dimen/work_fab_icon_size"
android:importantForAccessibility="no"
+ android:layout_marginEnd="@dimen/work_fab_icon_end_margin"
android:src="@drawable/ic_corp_off"
android:tint="@color/work_fab_icon_color"
android:scaleType="center"/>
@@ -43,7 +46,7 @@
android:includeFontPadding="false"
android:textDirection="locale"
android:text="@string/work_apps_pause_btn_text"
- android:layout_marginStart="@dimen/work_fab_text_start_margin"
+ android:layout_marginEnd="@dimen/work_fab_text_end_margin"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextHeadline"/>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 07343d7..7db41c3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -51,7 +51,7 @@
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"التواصل الاجتماعي"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"الصحة واللياقة البدنية"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"الطقس"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"محتوى مقترَح لك"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"اقتراحاتنا لك"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"تطبيقات \"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>\" المصغّرة على اليسار، والبحث والخيارات على اليمين"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index d4c18f0..6946ed5 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -124,7 +124,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>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index c411783..b57de6b 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -51,7 +51,7 @@
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</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 personalitzats"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggeriments per a tu"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la dreta, cerca i opcions a l\'esquerra"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# drecera}other{# dreceres}}"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 4cf1e8f..e9fef0c 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">"Nezbytnosti"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Základní"</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>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 848ebee..163739a 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -44,14 +44,14 @@
<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>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"اجتماعی"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"سلامتی و تناسب اندام"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"آبوهوا"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهادشده برای شما"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهاداتی برای شما"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزارکهای <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، جستجو و گزینهها در سمت راست"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ابزارک}one{# ابزارک}other{# ابزارک}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# میانبر}one{# میانبر}other{# میانبر}}"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 6d83820..600cde4 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -47,8 +47,8 @@
<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>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन से जुड़े ऐप्लिकेशन"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल मीडिया ऐप्लिकेशन"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"हेल्थ और फ़िटनेस वाले ऐप्लिकेशन"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"मौसम"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए ऐप्लिकेशन"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 72d23fa..03a30c4 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -45,7 +45,7 @@
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadva a kezdőképernyőhöz"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Javaslatok"</string>
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Legfontosabbak"</string>
- <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Hírlapok és folyóiratok"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Újságok és magazinok"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Az Ön relaxáló zónája"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Szórakozás"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Közösségi"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 0a1e4aa..215ac74 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -45,10 +45,10 @@
<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="news_widget_recommendation_category_label" msgid="6756167867113741310">"Газеттер мен журналдар"</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>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Әлеуметтік"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Қоғам"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Денсаулық және фитнес"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Ауа райы"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Сізге ұсынылғандар"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index b2f307b..4ab4ada 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -88,7 +88,7 @@
<string name="all_apps_button_work_label" msgid="7270707118948892488">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಪಟ್ಟಿ"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"ತೆಗೆದುಹಾಕಿ"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್ಇನ್ಸ್ಟಾಲ್"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ಖಾಸಗಿಯಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 9cecf07..d83a02b 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -45,7 +45,7 @@
<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="news_widget_recommendation_category_label" msgid="6756167867113741310">"ନ୍ୟୁଜ ଓ ମେଗାଜିନ"</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>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ସୋସିଆଲ"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index fc70150..6d5c699 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -51,7 +51,7 @@
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociais"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Saúde e fitness"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Meteorologia"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerido para si"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugestões para si"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à direita, pesquisa e opções à esquerda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}other{# atalhos}}"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index ee1caef..c0f3baa 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/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>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 07672c7..a3f5625 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Lägg till på startskärmen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g> har lagts till på startskärmen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Förslag"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Favoriter"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Viktigt"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nyheter och tidskrifter"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Koppla av"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Underhållning"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index daa90fa..4533fda 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/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">"Essentials"</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>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 5a88489..9e723dd 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ana ekrana ekle"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ana ekrana eklendi"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Öneriler"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Kaçırmamanız gerekenler"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Önemliler"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Haberler ve dergiler"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Huzur alanınız"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Eğlence"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8f5cce4..9552a57 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/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>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index c9b0610..89ccde3 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -45,7 +45,7 @@
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti bosh ekranga qoʻshildi"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Takliflar"</string>
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Asosiy ilovalar"</string>
- <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Gazeta va jurnallar"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Yangiliklar va jurnallar"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Sokin hududingiz"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hordiq"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Ijtimoiy"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 393a197..648a50c 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>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9ed1b72..f16c69b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -147,13 +147,15 @@
<dimen name="work_fab_height">56dp</dimen>
<dimen name="work_fab_radius">16dp</dimen>
<dimen name="work_fab_icon_size">24dp</dimen>
- <dimen name="work_fab_text_start_margin">8dp</dimen>
+ <dimen name="work_fab_icon_end_margin">12dp</dimen>
+ <dimen name="work_fab_text_end_margin">16dp</dimen>
<dimen name="work_card_padding_horizontal">10dp</dimen>
<dimen name="work_fab_width">214dp</dimen>
<dimen name="work_card_button_height">52dp</dimen>
<dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_fab_margin_bottom">20dp</dimen>
- <dimen name="work_mode_fab_padding">16dp</dimen>
+ <dimen name="work_mode_fab_background_start_padding">16dp</dimen>
+ <dimen name="work_mode_fab_background_end_padding">4dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
<dimen name="work_edu_card_margin">16dp</dimen>
<dimen name="work_edu_card_radius">16dp</dimen>
@@ -206,6 +208,9 @@
<!-- Margin applied to the recycler view with search bar & the list of widget apps below it. -->
<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>
@@ -473,6 +478,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 -->
@@ -493,7 +499,7 @@
<dimen name="ps_header_image_height">48dp</dimen>
<dimen name="ps_header_text_height">24dp</dimen>
<dimen name="ps_header_layout_margin">16dp</dimen>
- <dimen name="ps_header_settings_icon_margin_end">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..da5b709 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -487,8 +487,10 @@
<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>
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 51c7a05..eff748a 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -155,7 +155,7 @@
* Maps the touch (from 0..1) to the adapter position that should be visible.
* <p>Override in each subclass of this base class.
*/
- public abstract String scrollToPositionAtProgress(float touchFraction);
+ public abstract CharSequence scrollToPositionAtProgress(float touchFraction);
/**
* Updates the bounds for the scrollbar.
@@ -193,14 +193,4 @@
}
scrollToPosition(0);
}
-
- /**
- * Scrolls this recycler view to the bottom with easing and duration.
- */
- public void scrollToBottomWithMotion(int duration) {
- if (mScrollbar != null) {
- mScrollbar.reattachThumbToScroll();
- }
- smoothScrollBy(0, getAvailableScrollHeight(), Interpolators.EMPHASIZED, duration);
- }
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 2fd5ebd..f405b93 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -59,6 +59,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 +76,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,9 +230,8 @@
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) -> {
@@ -262,7 +262,7 @@
// Get the display info based on default display and interpolate it to existing display
Info defaultInfo = DisplayController.INSTANCE.get(context).getInfo();
- @DeviceType int defaultDeviceType = getDeviceType(defaultInfo);
+ @DeviceType int defaultDeviceType = defaultInfo.getDeviceType();
DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
defaultInfo,
getPredefinedDeviceProfiles(context, gridName, defaultDeviceType,
@@ -271,7 +271,7 @@
Context displayContext = context.createDisplayContext(display);
Info myInfo = new Info(displayContext);
- @DeviceType int deviceType = getDeviceType(myInfo);
+ @DeviceType int deviceType = myInfo.getDeviceType();
DisplayOption myDisplayOption = invDistWeightedInterpolate(
myInfo,
getPredefinedDeviceProfiles(context, gridName, deviceType,
@@ -295,6 +295,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.
*/
@@ -324,30 +329,13 @@
}
}
- private static @DeviceType int getDeviceType(Info displayInfo) {
- int flagPhone = 1 << 0;
- int flagTablet = 1 << 1;
-
- int type = displayInfo.supportedBounds.stream()
- .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
- .reduce(0, (a, b) -> a | b);
- if (type == (flagPhone | flagTablet)) {
- // device has profiles supporting both phone and table modes
- return TYPE_MULTI_DISPLAY;
- } else if (type == flagTablet) {
- return TYPE_TABLET;
- } else {
- return TYPE_PHONE;
- }
- }
-
public static String getCurrentGridName(Context context) {
return LauncherPrefs.get(context).get(GRID_NAME);
}
private String initGrid(Context context, String gridName) {
Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
- @DeviceType int deviceType = getDeviceType(displayInfo);
+ @DeviceType int deviceType = displayInfo.getDeviceType();
ArrayList<DisplayOption> allOptions =
getPredefinedDeviceProfiles(context, gridName, deviceType,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c91d4d0..dc7c349 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2508,7 +2508,13 @@
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
View item = container.getChildAt(itemIdx);
- if (op.test((ItemInfo) item.getTag())) {
+ if (item instanceof ViewGroup viewGroup) {
+ View view = mapOverViewGroup(viewGroup, op);
+ if (view != null) {
+ return view;
+ }
+ }
+ if (item.getTag() instanceof ItemInfo itemInfo && op.test(itemInfo)) {
return item;
}
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 50a597d..d2633e0 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -78,14 +78,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;
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 7fdfd72..9b0e0ec 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -447,8 +447,8 @@
IconCache iconCache = app.getIconCache();
final IntSet removedIds = new IntSet();
HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
- boolean isAppArchived = new PackageManagerHelper(
- mApp.getContext()).isAppArchivedForUser(packageName, user);
+ 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
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 80a8cea..b503739 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"
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/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 84b8ba1..87ac193 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -183,6 +183,7 @@
public static final int CONTAINER_SHORTCUTS = -107;
public static final int CONTAINER_SETTINGS = -108;
public static final int CONTAINER_TASKSWITCHER = -109;
+ public static final int CONTAINER_PRIVATESPACE = -110;
// Represents any of the extended containers implemented in non-AOSP variants.
public static final int EXTENDED_CONTAINERS = -200;
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/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 9792300..814d142 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -414,7 +414,7 @@
LauncherSettings.Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
- bindItem(item, accessibility, finishCallback);
+ bindItem(info, accessibility, finishCallback);
announceConfirmation(R.string.item_added_to_workspace);
} else if (item instanceof PendingAddItemInfo) {
PendingAddItemInfo info = (PendingAddItemInfo) item;
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 36a44cc..ba34f59 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -180,7 +180,7 @@
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
@Override
- public String scrollToPositionAtProgress(float touchFraction) {
+ public CharSequence scrollToPositionAtProgress(float touchFraction) {
int rowCount = mApps.getNumAppRows();
if (rowCount == 0) {
return "";
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 4d4b8d2..a810331 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -22,6 +22,9 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT;
import android.content.Context;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -65,11 +68,11 @@
*/
public static class FastScrollSectionInfo {
// The section name
- public final String sectionName;
+ public final CharSequence sectionName;
// The item position
public final int position;
- public FastScrollSectionInfo(String sectionName, int position) {
+ public FastScrollSectionInfo(CharSequence sectionName, int position) {
this.sectionName = sectionName;
this.position = position;
}
@@ -93,6 +96,7 @@
// The of ordered component names as a result of a search query
private final ArrayList<AdapterItem> mSearchResults = new ArrayList<>();
+ private final SpannableString mPrivateProfileAppScrollerBadge;
private BaseAllAppsAdapter<T> mAdapter;
private AppInfoComparator mAppNameComparator;
private int mNumAppsPerRowAllApps;
@@ -110,6 +114,10 @@
if (mAllAppsStore != null) {
mAllAppsStore.addUpdateListener(this);
}
+ mPrivateProfileAppScrollerBadge = new SpannableString(" ");
+ mPrivateProfileAppScrollerBadge.setSpan(new ImageSpan(context,
+ R.drawable.ic_private_profile_app_scroller_badge, ImageSpan.ALIGN_CENTER),
+ 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
/** Set the number of apps per row when device profile changes. */
@@ -353,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
@@ -383,6 +391,7 @@
private int addAppsWithSections(List<AppInfo> appList, int startPosition) {
String lastSectionName = null;
boolean hasPrivateApps = false;
+ int position = startPosition;
if (mPrivateProviderManager != null) {
hasPrivateApps = appList.stream().
allMatch(mPrivateProviderManager.getItemInfoMatcher());
@@ -403,11 +412,12 @@
// Create a new section if the section names do not match
if (!sectionName.equals(lastSectionName)) {
lastSectionName = sectionName;
- mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, startPosition));
+ mFastScrollerSections.add(new FastScrollSectionInfo(hasPrivateApps ?
+ mPrivateProfileAppScrollerBadge : sectionName, position));
}
- startPosition++;
+ position++;
}
- return startPosition;
+ return position;
}
/**
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 90ed3eb..551fa94 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -21,6 +21,7 @@
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;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
@@ -79,9 +80,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;
/**
@@ -104,7 +103,6 @@
}
}
};
- private Set<String> mPreInstalledSystemPackages = new HashSet<>();
private Intent mAppInstallerIntent = new Intent();
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
private boolean mPrivateSpaceSettingsAvailable;
@@ -114,6 +112,8 @@
private Runnable mOnPSHeaderAdded;
@Nullable
private RelativeLayout mPSHeader;
+ private final String mLockedStateContentDesc;
+ private final String mUnLockedStateContentDesc;
public PrivateProfileManager(UserManager userManager,
ActivityAllAppsContainerView<?> allApps,
@@ -127,6 +127,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. */
@@ -159,7 +163,6 @@
itemInfo.contentDescription = context.getResources().getString(
com.android.launcher3.R.string.ps_add_button_content_description);
itemInfo.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
- itemInfo.user = getProfileUser();
BaseAllAppsAdapter.AdapterItem item = new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_ICON);
item.itemInfo = itemInfo;
@@ -216,11 +219,27 @@
resetPrivateSpaceDecorator(updatedState);
}
- /** Opens the Private Space Settings Page. */
- public void openPrivateSpaceSettings() {
+ /**
+ * Opens the Private Space Settings Page.
+ *
+ * @param view the view that was clicked to open the settings page and which will be the same
+ * view to animate back. Otherwise if there is no view, simply start the activity.
+ */
+ public void openPrivateSpaceSettings(View view) {
if (mPrivateSpaceSettingsAvailable) {
- mAllApps.getContext().startActivity(
- ApiWrapper.INSTANCE.get(mAllApps.getContext()).getPrivateSpaceSettingsIntent());
+ Context context = mAllApps.getContext();
+ Intent intent = ApiWrapper.INSTANCE.get(context).getPrivateSpaceSettingsIntent();
+ if (view == null) {
+ context.startActivity(intent);
+ return;
+ }
+ ActivityContext activityContext = ActivityContext.lookupContext(context);
+ AppInfo itemInfo = new AppInfo();
+ itemInfo.id = CONTAINER_PRIVATESPACE;
+ itemInfo.componentName = intent.getComponent();
+ itemInfo.container = CONTAINER_PRIVATESPACE;
+ view.setTag(itemInfo);
+ activityContext.startActivitySafely(view, intent, itemInfo);
}
}
@@ -248,8 +267,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);
}
@@ -333,10 +350,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} */
@@ -385,11 +404,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);
}
@@ -399,9 +420,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);
}
}
@@ -423,7 +449,7 @@
settingsButton.setOnClickListener(
view -> {
logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
- openPrivateSpaceSettings();
+ openPrivateSpaceSettings(view);
});
} else {
settingsButton.setVisibility(GONE);
@@ -747,6 +773,7 @@
}
boolean isPrivateSpaceItem(BaseAllAppsAdapter.AdapterItem item) {
- return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null;
+ return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null
+ || (item.itemInfo instanceof PrivateSpaceInstallAppButtonInfo);
}
}
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index eb7d429..6049574 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -15,14 +15,10 @@
*/
package com.android.launcher3.allapps;
-import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth;
-
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.View;
import android.view.WindowInsets;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -35,7 +31,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
-import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.views.ActivityContext;
/**
@@ -53,12 +48,11 @@
private final Rect mImeInsets = new Rect();
private int mFlags;
private final ActivityContext mActivityContext;
+ private final Context mContext;
// Threshold when user scrolls up/down to determine when should button extend/collapse
private final int mScrollThreshold;
- private ImageView mIcon;
private TextView mTextView;
- private final StatsLogManager mStatsLogManager;
public WorkModeSwitch(@NonNull Context context) {
@@ -71,16 +65,15 @@
public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mContext = context;
mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
mActivityContext = ActivityContext.lookupContext(getContext());
- mStatsLogManager = mActivityContext.getStatsLogManager();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mIcon = findViewById(R.id.work_icon);
mTextView = findViewById(R.id.pause_text);
setSelected(true);
KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
@@ -114,13 +107,8 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- View parent = (View) getParent();
boolean isRtl = Utilities.isRtl(getResources());
- Rect allAppsPadding = mActivityContext.getDeviceProfile().allAppsPadding;
- int size = parent.getWidth() - parent.getPaddingLeft() - parent.getPaddingRight()
- - (allAppsPadding.left + allAppsPadding.right);
- int tabWidth = getTabWidth(getContext(), size);
- int shift = (size - tabWidth) / 2 + (isRtl ? allAppsPadding.left : allAppsPadding.right);
+ int shift = mActivityContext.getDeviceProfile().getAllAppsIconStartMargin(mContext);
setTranslationX(isRtl ? shift : -shift);
}
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index ec45415..19c3ebe 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -31,7 +31,6 @@
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;
@@ -144,7 +143,7 @@
@Override
public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus && !FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+ if (!hasFocus) {
mInput.hideKeyboard();
}
}
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/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 0e4b48e..50d2b43 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -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;
@@ -88,14 +87,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 +100,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;
@@ -136,13 +131,10 @@
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);
+ super(base);
mIdp = idp;
- mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
- mObjectMap.put(LauncherAppState.INSTANCE,
+ putObject(InvariantDeviceProfile.INSTANCE, idp);
+ putObject(LauncherAppState.INSTANCE,
new LauncherAppState(this, null /* iconCacheFileName */));
}
@@ -419,7 +411,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;
}
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index ce563b7..3fa6da4 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;
@@ -85,6 +86,7 @@
final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
final IntArray addedWorkspaceScreensFinal = new IntArray();
+ final Context context = app.getContext();
synchronized (dataModel) {
IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
@@ -99,7 +101,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 +114,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,8 +123,8 @@
}
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.
@@ -135,7 +137,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");
}
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index a1a05f4..39c1243 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -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;
}
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/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index a742c75..77bc32e 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -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 = PackageManagerHelper.INSTANCE.get(mApp.getContext());
mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
mIconCache = mApp.getIconCache();
mUserManagerState = userManagerState;
@@ -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);
@@ -447,7 +448,7 @@
mUserCache, mUserManagerState, mLauncherApps, mPendingPackages,
mShortcutKeyToPinnedShortcuts, mApp, mBgDataModel,
mWidgetProvidersMap, installingPkgs, isSdCardReady,
- widgetInflater, pmHelper, iconRequestInfos, unlockedUsers,
+ widgetInflater, mPmHelper, iconRequestInfos, unlockedUsers,
allDeepShortcuts);
while (!mStopped && c.moveToNext()) {
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..1cb5215 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -78,7 +78,7 @@
if (!matchingWorkspaceItems.isEmpty()) {
if (mShortcuts.isEmpty()) {
- PackageManagerHelper packageManagerHelper = new PackageManagerHelper(
+ PackageManagerHelper packageManagerHelper = PackageManagerHelper.INSTANCE.get(
app.getContext());
// Verify that the app is indeed installed.
if (!packageManagerHelper.isAppInstalled(mPackageName, mUser)
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 6b153dd..cea4380 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -184,6 +184,9 @@
}
}
}
+ if (intent.`package` == null) {
+ intent.`package` = targetPkg
+ }
// else if cn == null => can't infer much, leave it
// else if !validPkg => could be restored icon or missing sd-card
when {
@@ -329,8 +332,12 @@
}
val activityInfo = c.launcherActivityInfo
if (activityInfo != null) {
- AppInfo.updateRuntimeFlagsForActivityTarget(info, activityInfo,
- userCache.getUserInfo(c.user), ApiWrapper.INSTANCE[app.context])
+ AppInfo.updateRuntimeFlagsForActivityTarget(
+ info,
+ activityInfo,
+ userCache.getUserInfo(c.user),
+ ApiWrapper.INSTANCE[app.context]
+ )
}
if (
(c.restoreFlag != 0 ||
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 8c3efd7..72e85c7 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -427,12 +427,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 +524,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/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/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/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/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/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 ff95212..8806e27 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -19,6 +19,9 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
+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_KEY;
import static com.android.launcher3.Utilities.dpiFromPx;
@@ -47,6 +50,7 @@
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.InvariantDeviceProfile.DeviceType;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
@@ -466,6 +470,23 @@
public int getDensityDpi() {
return densityDpi;
}
+
+ public @DeviceType int getDeviceType() {
+ int flagPhone = 1 << 0;
+ int flagTablet = 1 << 1;
+
+ int type = supportedBounds.stream()
+ .mapToInt(bounds -> isTablet(bounds) ? flagTablet : flagPhone)
+ .reduce(0, (a, b) -> a | b);
+ if (type == (flagPhone | flagTablet)) {
+ // device has profiles supporting both phone and tablet modes
+ return TYPE_MULTI_DISPLAY;
+ } else if (type == flagTablet) {
+ return TYPE_TABLET;
+ } else {
+ return TYPE_PHONE;
+ }
+ }
}
/**
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..3684f56 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -56,11 +56,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
@@ -75,6 +79,9 @@
mLauncherApps = Objects.requireNonNull(context.getSystemService(LauncherApps.class));
}
+ @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.
@@ -170,10 +177,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 +197,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);
}
}
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..4b004f3 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;
@@ -305,12 +306,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 +475,9 @@
NavigationMode.THREE_BUTTONS;
}
+ @Override
+ public void close() { }
+
/**
* @see DisplayCutout#getSafeInsets
*/
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 9f6e8f8..5ce455a 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -25,6 +25,8 @@
import static com.android.launcher3.allapps.AllAppsTransitionController.REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS;
import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
@@ -135,6 +137,7 @@
protected final AnimatedFloat mSwipeToDismissProgress =
new AnimatedFloat(this::onUserSwipeToDismissProgressChanged, 0f);
protected boolean mIsDismissInProgress;
+ private View mViewToAnimateInSwipeToDismiss = this;
private @Nullable Drawable mContentBackground;
private @Nullable View mContentBackgroundParentView;
@@ -286,18 +289,37 @@
@Override
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public void onBackStarted(BackEvent backEvent) {
+ super.onBackStarted(backEvent);
+ mViewToAnimateInSwipeToDismiss = shouldAnimateContentViewInBackSwipe() ? mContent : this;
+ }
+
+ @Override
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public void onBackProgressed(BackEvent backEvent) {
final float progress = backEvent.getProgress();
float deceleratedProgress = Interpolators.BACK_GESTURE.getInterpolation(progress);
mSwipeToDismissProgress.updateValue(deceleratedProgress);
}
+ /**
+ * During predictive back swipe, the default behavior is to scale {@link AbstractSlideInView}
+ * during back swipe. This method allow subclass to scale {@link #mContent}, typically to exit
+ * search mode.
+ *
+ * <p>Note that this method can be expensive, and should only be called from
+ * {@link #onBackStarted(BackEvent)}, not from {@link #onBackProgressed(BackEvent)}.
+ */
+ protected boolean shouldAnimateContentViewInBackSwipe() {
+ return false;
+ }
+
protected void onUserSwipeToDismissProgressChanged() {
float progress = mSwipeToDismissProgress.value;
mIsDismissInProgress = progress > 0f;
float scale = PREDICTIVE_BACK_MIN_SCALE + (1 - PREDICTIVE_BACK_MIN_SCALE) * (1f - progress);
- SCALE_PROPERTY.set(this, scale);
+ SCALE_PROPERTY.set(mViewToAnimateInSwipeToDismiss, scale);
setClipChildren(!mIsDismissInProgress);
setClipToPadding(!mIsDismissInProgress);
mContent.setClipChildren(!mIsDismissInProgress);
@@ -312,9 +334,32 @@
}
protected void animateSwipeToDismissProgressToStart() {
- mSwipeToDismissProgress.animateToValue(0f)
- .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
- .start();
+ ObjectAnimator objectAnimator = mSwipeToDismissProgress.animateToValue(0f)
+ .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS);
+
+ // If we are animating a different view, we should reset the animating view back to
+ // AbstractSlideInView as it is the default view to animate.
+ if (this != mViewToAnimateInSwipeToDismiss) {
+ objectAnimator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {}
+
+ @Override
+ public void onAnimationStart(Animator animator) {}
+ });
+ }
+
+ objectAnimator.start();
}
@Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index f76b53b..f560311 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -55,6 +55,7 @@
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;
@@ -282,6 +283,8 @@
} else if (btvIcon instanceof PreloadIconDrawable) {
// Force the progress bar to display.
drawable = btvIcon;
+ } else if (originalView instanceof ImageView) {
+ drawable = ((ImageView) originalView).getDrawable();
} else {
int width = (int) pos.width();
int height = (int) pos.height();
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 8408cc7..df8f635 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -30,6 +30,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Property;
@@ -121,7 +122,7 @@
// Fast scroller popup
private TextView mPopupView;
private boolean mPopupVisible;
- private String mPopupSectionName;
+ private CharSequence mPopupSectionName;
private Insets mSystemGestureInsets;
protected FastScrollRecyclerView mRv;
@@ -307,13 +308,13 @@
// Update the fastscroller section name at this touch position
int bottom = mRv.getScrollbarTrackHeight() - mThumbHeight;
float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffsetY));
- String sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
+ CharSequence sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
if (!sectionName.equals(mPopupSectionName)) {
mPopupSectionName = sectionName;
mPopupView.setText(sectionName);
performHapticFeedback(CLOCK_TICK);
}
- animatePopupVisibility(!sectionName.isEmpty());
+ animatePopupVisibility(!TextUtils.isEmpty(sectionName));
mLastTouchY = boundedY;
setThumbOffsetY((int) mLastTouchY);
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index aa797ab..749554c 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,8 +16,6 @@
package com.android.launcher3.widget;
import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
-import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
import static com.android.launcher3.Flags.enableWidgetTapToAdd;
import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
@@ -143,9 +141,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) {
@@ -320,19 +326,8 @@
MeasureSpec.getSize(heightMeasureSpec));
}
- private int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
- // All bottom-sheets showing widgets will be full-width across all devices.
- if (enableCategorizedWidgetSuggestions()) {
- return 0;
- }
- if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
- return getResources().getDimensionPixelSize(
- R.dimen.widget_picker_landscape_tablet_left_right_margin);
- }
- if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
- return getResources().getDimensionPixelSize(
- R.dimen.widget_picker_two_panels_left_right_margin);
- }
+ /** Returns the horizontal margins to be applied to the widget sheet. **/
+ protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
return deviceProfile.allAppsLeftRightMargin;
}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index ab007fb..ea167d7 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -110,6 +110,7 @@
private int mSourceContainer = CONTAINER_WIDGETS_TRAY;
private CancellableTask mIconLoadRequest;
+ private boolean mIsShowingAddButton = false;
public WidgetCell(Context context) {
this(context, null);
@@ -534,6 +535,9 @@
* @param callback Callback to be set on the button.
*/
public void showAddButton(View.OnClickListener callback) {
+ if (mIsShowingAddButton) return;
+ mIsShowingAddButton = true;
+
mWidgetAddButton.setAlpha(0F);
mWidgetAddButton.setVisibility(VISIBLE);
mWidgetAddButton.setOnClickListener(callback);
@@ -555,6 +559,9 @@
* Hide tap to add button.
*/
public void hideAddButton(boolean animate) {
+ if (!mIsShowingAddButton) return;
+ mIsShowingAddButton = false;
+
mWidgetAddButton.setOnClickListener(null);
mWidgetAddButton.animate().cancel();
mWidgetTextContainer.animate().cancel();
@@ -579,4 +586,8 @@
.alpha(1F)
.setDuration(ADD_BUTTON_FADE_DURATION_MS);
}
+
+ public boolean isShowingAddButton() {
+ return mIsShowingAddButton;
+ }
}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 97aa67d..3be6c68 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,22 +49,6 @@
* 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;
@@ -119,9 +102,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
@@ -216,6 +196,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/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 c6cbb60..28eeb10 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -902,11 +902,23 @@
return isFoldUnFold || useDifferentLayoutOnOrientationChange;
}
+ /**
+ * In widget search mode, we should scale down content inside widget bottom sheet, rather
+ * than the whole bottom sheet, to indicate we will navigate back within the widget
+ * bottom sheet.
+ */
+ @Override
+ public boolean shouldAnimateContentViewInBackSwipe() {
+ return mIsInSearchMode;
+ }
+
@Override
public void onBackInvoked() {
if (mIsInSearchMode) {
mSearchBar.reset();
- animateSwipeToDismissProgressToStart();
+ // Posting animation to next frame will let widget sheet finish updating UI first, and
+ // make animation smoother.
+ post(this::animateSwipeToDismissProgressToStart);
} else {
super.onBackInvoked();
}
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..03af0cb 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -123,6 +123,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/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 698e764..a47818f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -73,7 +73,7 @@
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
@Override
- public String scrollToPositionAtProgress(float touchFraction) {
+ public CharSequence scrollToPositionAtProgress(float touchFraction) {
// Skip early if widgets are not bound.
if (isModelNotReady()) {
return "";
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index cb8b14e..2a2feed 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -23,14 +23,12 @@
import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
import android.content.Context;
-import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Process;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewOutlineProvider;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -39,6 +37,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Px;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.model.data.PackageItemInfo;
@@ -79,21 +78,6 @@
private int mActivePage = -1;
private PackageUserKey mSelectedHeader;
- private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(
- 0,
- 0,
- view.getMeasuredWidth(),
- view.getMeasuredHeight() - getResources().getDimensionPixelSize(
- R.dimen.widget_list_horizontal_margin_two_pane),
- view.getResources().getDimensionPixelSize(
- R.dimen.widget_list_top_bottom_corner_radius)
- );
- }
- };
-
public WidgetsTwoPaneSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@@ -137,11 +121,8 @@
mHeaderTitle = mContent.findViewById(R.id.title);
mRightPane = mContent.findViewById(R.id.right_pane);
- mRightPane.setOutlineProvider(mViewOutlineProviderRightPane);
mRightPaneScrollView = mContent.findViewById(R.id.right_pane_scroll_view);
mRightPaneScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
- mRightPaneScrollView.setOutlineProvider(mViewOutlineProvider);
- mRightPaneScrollView.setClipToOutline(true);
mPrimaryWidgetListView = findViewById(R.id.primary_widgets_list_view);
mPrimaryWidgetListView.setOutlineProvider(mViewOutlineProvider);
@@ -155,6 +136,26 @@
}
@Override
+ protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
+ if (enableCategorizedWidgetSuggestions()) {
+ // two pane picker is full width for fold as well as tablet.
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_two_panels_left_right_margin);
+ }
+ if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+ // enableUnfoldedTwoPanePicker made two pane picker full-width for fold only.
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_two_panels_left_right_margin);
+ }
+ if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
+ // non-fold tablet landscape margins (ag/22163531)
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_landscape_tablet_left_right_margin);
+ }
+ return deviceProfile.allAppsLeftRightMargin;
+ }
+
+ @Override
protected void onUserSwipeToDismissProgressChanged() {
super.onUserSwipeToDismissProgressChanged();
boolean isSwipeToDismissInProgress = mSwipeToDismissProgress.value > 0;
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/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 27dd2a9..a9b75ea 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"
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..108db6c 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -174,13 +174,11 @@
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 OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index 0009a4e..002f496 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -52,17 +52,11 @@
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;
@@ -233,13 +227,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 +242,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/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..aefc2db 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -300,13 +300,7 @@
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)
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 4021b17..2a4d21d 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -209,7 +209,7 @@
ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true);
- mPrivateProfileManager.openPrivateSpaceSettings();
+ mPrivateProfileManager.openPrivateSpaceSettings(null);
Mockito.verify(mContext).startActivity(acIntent.capture());
assertEquals("Intent Action is different",
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/model/WorkspaceItemProcessorTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 0023ec8..c2e73fc 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -66,7 +66,6 @@
@Mock private lateinit var mockBgDataModel: BgDataModel
@Mock private lateinit var mockContext: Context
@Mock private lateinit var mockAppState: LauncherAppState
- @Mock private lateinit var mockIntent: Intent
@Mock private lateinit var mockPmHelper: PackageManagerHelper
@Mock private lateinit var mockLauncherApps: LauncherApps
@Mock private lateinit var mockCursor: LoaderCursor
@@ -74,6 +73,7 @@
@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
@@ -93,11 +93,11 @@
mockBgDataModel = mock<BgDataModel>()
componentName = ComponentName("package", "class")
unlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
- mockIntent =
- mock<Intent>().apply {
- whenever(component).thenReturn(componentName)
- whenever(`package`).thenReturn("pkg")
- whenever(getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)).thenReturn("")
+ intent =
+ Intent().apply {
+ component = componentName
+ `package` = "pkg"
+ putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
}
mockContext =
mock<Context>().apply {
@@ -113,7 +113,7 @@
mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(componentName.packageName, userHandle))
- .thenReturn(mockIntent)
+ .thenReturn(intent)
}
mockLauncherApps =
mock<LauncherApps>().apply {
@@ -127,19 +127,17 @@
id = 1
restoreFlag = 1
serialNumber = 101
- whenever(parseIntent()).thenReturn(mockIntent)
+ whenever(parseIntent()).thenReturn(intent)
whenever(markRestored()).doAnswer { restoreFlag = 0 }
- whenever(updater().put(Favorites.INTENT, mockIntent.toUri(0)).commit())
- .thenReturn(1)
+ whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
whenever(getAppShortcutInfo(any(), any(), any(), any()))
.thenReturn(mockWorkspaceInfo)
whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
}
mockUserCache =
mock<UserCache>().apply {
- val userIconInfo = mock<UserIconInfo>().apply() {
- whenever(isPrivate).thenReturn(false)
- }
+ val userIconInfo =
+ mock<UserIconInfo>().apply() { whenever(isPrivate).thenReturn(false) }
whenever(getUserInfo(any())).thenReturn(userIconInfo)
}
@@ -198,9 +196,11 @@
fun `When user is null then mark item deleted`() {
// Given
mockCursor = mock<LoaderCursor>().apply { id = 1 }
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
+
// Then
verify(mockCursor).markDeleted("User has been deleted for item id=1", PROFILE_DELETED)
verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
@@ -210,8 +210,9 @@
fun `When app has null intent then mark deleted`() {
// Given
mockCursor.apply { whenever(parseIntent()).thenReturn(null) }
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
verify(mockCursor).markDeleted("Null intent from db for item id=1", MISSING_INFO)
@@ -222,13 +223,13 @@
fun `When app has null target package then mark deleted`() {
// Given
- mockIntent.apply {
- whenever(component).thenReturn(null)
- whenever(`package`).thenReturn(null)
+ intent.apply {
+ component = null
+ `package` = null
}
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -241,11 +242,11 @@
// Given
componentName = ComponentName("", "")
- whenever(mockIntent.component).thenReturn(componentName)
- whenever(mockCursor.parseIntent()).thenReturn(mockIntent)
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+ intent.component = componentName
+ intent.`package` = ""
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -256,10 +257,8 @@
@Test
fun `When valid app then mark restored`() {
- // Given
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
-
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -284,18 +283,18 @@
mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(componentName.packageName, userHandle))
- .thenReturn(mockIntent)
+ .thenReturn(intent)
}
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
assertWithMessage("item restoreFlag should be set to 0")
.that(mockCursor.restoreFlag)
.isEqualTo(0)
- verify(mockCursor.updater().put(Favorites.INTENT, mockIntent.toUri(0))).commit()
+ verify(mockCursor.updater().put(Favorites.INTENT, intent.toUri(0))).commit()
assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
}
@@ -313,9 +312,9 @@
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(componentName.packageName, userHandle)).thenReturn(null)
}
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -349,13 +348,13 @@
whenever(disabledReason).thenReturn(0)
whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
}
- val shortcutKey = ShortcutKey.fromIntent(mockIntent, mockCursor.user)
+ val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
iconRequestInfos = mutableListOf()
- itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
// When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
itemProcessorUnderTest.processItem()
// Then
@@ -375,9 +374,9 @@
mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
iconRequestInfos = mutableListOf()
keyToPinnedShortcutsMap = hashMapOf()
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -394,6 +393,45 @@
}
@Test
+ fun `When valid Pinned Deep Shortcut with null intent package then use targetPkg`() {
+
+ // Given
+ mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+ val expectedShortcutInfo =
+ mock<ShortcutInfo>().apply {
+ whenever(id).thenReturn("")
+ whenever(`package`).thenReturn("")
+ whenever(activity).thenReturn(mock())
+ whenever(longLabel).thenReturn("")
+ whenever(isEnabled).thenReturn(true)
+ whenever(disabledMessage).thenReturn("")
+ whenever(disabledReason).thenReturn(0)
+ whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
+ }
+ iconRequestInfos = mutableListOf()
+ // Make sure shortcuts map has expected key from expected package
+ intent.`package` = componentName.packageName
+ val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
+ keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+ // set intent package back to null to test scenario
+ intent.`package` = null
+
+ // When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ assertThat(iconRequestInfos).isEmpty()
+ assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+ verify(mockCursor).markRestored()
+ verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
fun `When processing Folder then create FolderInfo and mark restored`() {
val actualFolderInfo = FolderInfo()
mockBgDataModel =
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..70a3dd0 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;
@@ -196,6 +197,7 @@
}
+ @KeepRecordOnSuccess
@ScreenRecord // b/322823478
@Test
public void testEdu() {
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..2e57ad5 100644
--- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -45,6 +45,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
@@ -123,6 +124,7 @@
whenever(displayManager.getDisplay(any())).thenReturn(display)
// Mock resources
+ doReturn(context).whenever(context).applicationContext
whenever(resources.configuration).thenReturn(configuration)
whenever(context.resources).thenReturn(resources)
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/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..ba8121f 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;
@@ -2400,13 +2398,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/PrivateSpaceContainer.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
index 2c16e01..daddd2f 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;
/**
@@ -57,4 +59,16 @@
private void verifyDividerIsPresent() {
mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID);
}
+
+ /**
+ * Verifies that a user installed app is present above the divider.
+ */
+ public void verifyInstalledAppIsPresent(String appName) {
+ HomeAppIcon appIcon = mLauncher.getAllApps().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);
+ }
}